Skip to content

Commit

Permalink
chore(server): rewrite resolveHTTPResponse with Fetch (#5684)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Nick Lucas <me@nicklucas.co.uk>
Co-authored-by: Sheraff <fpellet@ensc.fr>
  • Loading branch information
3 people committed Apr 30, 2024
1 parent 5ad570a commit 01bb2ea
Show file tree
Hide file tree
Showing 89 changed files with 1,574 additions and 2,296 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ jobs:
dir:
[
.experimental/next-app-dir,
.experimental/next-formdata,
.test/diagnostics-big-router,
.test/internal-types-export,
.test/ssg,
Expand All @@ -85,6 +84,7 @@ jobs:
express-server,
fastify-server,
minimal-react,
next-formdata,
next-minimal-starter,
next-prisma-starter,
next-prisma-todomvc,
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-tmp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ on:
push:
branches:
# Replace this with the branch you want to release from
# 👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
- 'issues/5659-multi-body-read'
# 👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆
# 👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇👇
- '04-26-resolveResponse-and-multi'
# 👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆
paths:
- '.github/workflows/release-tmp.yml'
- 'packages/**'
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/subtree.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
next-big-router,
minimal,
minimal-react,
.experimental/next-formdata,
next-formdata,
.experimental/next-app-dir,
]

Expand Down
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,11 @@ The most complex types are also in this area because we must keep track of the c

#### Handling a Request and Forming a Response

The core implementation for HTTP handling is contained in [`resolveHTTPResponse`](packages/server/src/http/resolveHTTPResponse.ts) where requests are handled and an object representing a response is created. This function deals with handling different methods (`query` and `mutation` have different specs), batching, streaming, etc. so it is an excellent place to get an overview of the complete process of handling a request and forming a response. If you want to learn more about the specification that we implement, read [this docs page](https://trpc.io/docs/rpc).
The core implementation for HTTP handling is contained in [`resolveResponse`](packages/server/src/http/resolveHTTPResponse.ts) where [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)s are handled and a [`Response`-object](https://developer.mozilla.org/en-US/docs/Web/API/Response) is created. This function deals with handling different methods (`query` and `mutation` have different specs), batching, streaming, etc. so it is an excellent place to get an overview of the complete process of handling a request and forming a response. If you want to learn more about the specification that we implement, read [this docs page](https://trpc.io/docs/rpc).

#### Adapting Requests and Responses

Adapters are what connect our framework-agnostic HTTP handling into a server response. We offer official adapters for some popular frameworks, although adapters can also be third-party. Adapters "adapt" their framework's request object into a common format and the object response from `resolveHTTPResponse` into their framework-specific responses. This keeps tRPC framework-agnostic, an important principle that allows it to be used in any environment.
Adapters are what connect our framework-agnostic HTTP handling into a server response. We offer official adapters for some popular frameworks, although adapters can also be third-party. Adapters "adapt" their framework's request object into a common format and the object response from `resolveResponse` into their framework-specific responses. This keeps tRPC framework-agnostic, an important principle that allows it to be used in any environment.

### `@trpc/client`

Expand Down
28 changes: 0 additions & 28 deletions examples/.experimental/next-formdata/README.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,19 @@ export function SendMultipartFormDataButton() {
return (
<button
onClick={() => {
const data = new FormData();
const fd = new FormData();

data.set('name', 'John Doe');
data.set('occupation', 'tRPC Extraordinaire');
fd.set('name', 'John Doe');
fd.set('occupation', 'tRPC Extraordinaire');

mutation.mutate(data);
fd.set(
'about',
new File(['hi bob'], 'bob.txt', {
type: 'text/plain',
}),
);

mutation.mutate(fd);
}}
>
Send FormData
Expand Down
77 changes: 39 additions & 38 deletions examples/minimal-content-types/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,63 @@
* This is the API-handler of your app that contains all your API routes.
* On a bigger app, you will probably want to split this file up into multiple files.
*/
import { initTRPC, parseOctetInput } from '@trpc/server';
import { initTRPC } from '@trpc/server';
import { createHTTPServer } from '@trpc/server/adapters/standalone';
import { octetInputParser } from '@trpc/server/http';
import cors from 'cors';
import type { z } from 'zod';
import { z } from 'zod';

const t = initTRPC.create();

const publicProcedure = t.procedure;
const router = t.router;

// A fake type parser which just expects the appropriate type to be passed through
function asType<TOut, TIn = unknown>(): z.ZodType<TOut, any, TIn> {
return {
parse: (input: unknown) => {
console.log('parser received', input);
return input as TOut;
},
} as z.ZodType<TOut, any, TIn>;
}

const appRouter = router({
// Input parsers set! (should expect the input to be loaded into memory)
formData: publicProcedure.input(asType<FormData>()).mutation(({ input }) => {
const object = {} as Record<string, unknown>;
input.forEach((value, key) => (object[key] = value));

console.log('FormData: ', object, input);

return {
text: 'ACK',
data: object,
};
}),
file: publicProcedure
.input(parseOctetInput<File>())
formData: publicProcedure
.input(z.instanceof(FormData))
.mutation(async ({ input }) => {
const chunks = [];

const reader = input.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
const object = {} as Record<string, unknown>;
for (const [key, value] of input.entries()) {
if (value instanceof File) {
object[key] = {
name: value.name,
type: value.type,
size: value.size,
text: await value.text(),
};
} else {
object[key] = value;
}
chunks.push(value);
}

const content = Buffer.concat(chunks).toString('utf-8');

console.log('File: ', content);
console.log('FormData: ', object);

return {
text: 'ACK',
data: content,
data: object,
};
}),
file: publicProcedure.input(octetInputParser).mutation(async ({ input }) => {
const chunks = [];

const reader = input.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
chunks.push(value);
}

const content = Buffer.concat(chunks).toString('utf-8');

console.log('File: ', content);

return {
text: 'ACK',
data: content,
};
}),
});

// export only the type definition of the API
Expand Down
1 change: 1 addition & 0 deletions examples/minimal-content-types/server/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"moduleResolution": "node",
"esModuleInterop": true,
"target": "ESNext",
"strict": true,
"outDir": "dist"
}
Expand Down
File renamed without changes.
12 changes: 12 additions & 0 deletions examples/next-formdata/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Next.js + tRPC + `FormData`

This example showcases how to use tRPC with `FormData`.

## Setup

```bash
npx create-next-app --example https://github.com/trpc/trpc --example-path examples/next-formdata trpc-formdata
cd trpc-formdata
npm i
npm run dev
```
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 1 addition & 11 deletions packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,6 @@
"require": "./dist/adapters/next.js",
"default": "./dist/adapters/next.js"
},
"./adapters/node-http/content-type/form-data": {
"import": "./dist/adapters/node-http/content-type/form-data/index.mjs",
"require": "./dist/adapters/node-http/content-type/form-data/index.js",
"default": "./dist/adapters/node-http/content-type/form-data/index.js"
},
"./adapters/node-http/content-type/json": {
"import": "./dist/adapters/node-http/content-type/json/index.mjs",
"require": "./dist/adapters/node-http/content-type/json/index.js",
"default": "./dist/adapters/node-http/content-type/json/index.js"
},
"./adapters/node-http": {
"import": "./dist/adapters/node-http/index.mjs",
"require": "./dist/adapters/node-http/index.js",
Expand Down Expand Up @@ -128,7 +118,7 @@
"devDependencies": {
"@fastify/websocket": "^10.0.1",
"@tanstack/react-query": "^5.25.0",
"@types/aws-lambda": "^8.10.97",
"@types/aws-lambda": "^8.10.137",
"@types/express": "^4.17.17",
"@types/hash-sum": "^1.0.0",
"@types/node": "^20.10.0",
Expand Down
2 changes: 0 additions & 2 deletions packages/server/rollup.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ export const input = [
'src/adapters/fetch/index.ts',
'src/adapters/next-app-dir.ts',
'src/adapters/next.ts',
'src/adapters/node-http/content-type/form-data/index.ts',
'src/adapters/node-http/content-type/json/index.ts',
'src/adapters/node-http/index.ts',
'src/adapters/standalone.ts',
'src/adapters/ws.ts',
Expand Down
19 changes: 7 additions & 12 deletions packages/server/src/@trpc/server/http.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
export {
getHTTPStatusCode,
getHTTPStatusCodeFromError,
resolveResponse,
} from '../../unstable-core-do-not-import';
export { resolveHTTPResponse } from '../../unstable-core-do-not-import';
export type {
BaseHandlerOptions,
HTTPBaseHandlerOptions,
HTTPHeaders,
HTTPRequest,
HTTPResponse,
OnErrorFunction,
ProcedureCall,
HTTPErrorHandler,
/**
* @deprecated Use `HTTPErrorHandler` instead
*/
HTTPErrorHandler as OnErrorFunction,
ResolveHTTPRequestOptionsContextFn,
ResponseChunk,
ResponseMeta,
ResponseMetaFn,
TRPCRequestInfo,
} from '../../unstable-core-do-not-import';

export { getBatchStreamFormatter } from '../../unstable-core-do-not-import';
export type {
BaseContentTypeHandler,
BodyResult,
} from '../../unstable-core-do-not-import';
export { toURL } from '../../unstable-core-do-not-import';
export { octetInputParser, toURL } from '../../unstable-core-do-not-import';
3 changes: 0 additions & 3 deletions packages/server/src/@trpc/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export {
type AnySubscriptionProcedure as AnyTRPCSubscriptionProcedure,
type ProcedureOptions as TRPCProcedureOptions,
type CreateContextCallback,
type WrapCreateContext,
type MutationProcedure as TRPCMutationProcedure,
type QueryProcedure as TRPCQueryProcedure,
type SubscriptionProcedure as TRPCSubscriptionProcedure,
Expand Down Expand Up @@ -104,5 +103,3 @@ export {
*/
export type inferAsyncReturnType<TFunction extends (...args: any[]) => any> =
Awaited<ReturnType<TFunction>>;

export { parseOctetInput } from '../../unstable-core-do-not-import/contentTypeParsers';
Loading

0 comments on commit 01bb2ea

Please sign in to comment.