Skip to content

Commit

Permalink
fix(server): fix fetch adapter trailing slash in url (#5090)
Browse files Browse the repository at this point in the history
  • Loading branch information
KATT committed Nov 23, 2023
1 parent 0985e9d commit 578a394
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 61 deletions.
15 changes: 12 additions & 3 deletions packages/server/src/adapters/fetch/fetchRequestHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ export type FetchHandlerRequestOptions<TRouter extends AnyRouter> =
endpoint: string;
};

const trimSlashes = (path: string): string => {
path = path.startsWith('/') ? path.slice(1) : path;
path = path.endsWith('/') ? path.slice(0, -1) : path;

return path;
};

export async function fetchRequestHandler<TRouter extends AnyRouter>(
opts: FetchHandlerRequestOptions<TRouter>,
): Promise<Response> {
Expand All @@ -20,9 +27,11 @@ export async function fetchRequestHandler<TRouter extends AnyRouter>(
};

const url = new URL(opts.req.url);
const path = url.pathname.slice(
opts.endpoint.length + (opts.endpoint.endsWith('/') ? 0 : 1),
);

const pathname = trimSlashes(url.pathname);
const endpoint = trimSlashes(opts.endpoint);
const path = trimSlashes(pathname.slice(endpoint.length));

const req: HTTPRequest = {
query: url.searchParams,
method: opts.req.method,
Expand Down
81 changes: 23 additions & 58 deletions packages/tests/server/adapters/fetch.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @vitest-environment miniflare
/// <reference types="@cloudflare/workers-types" />
import '../___packages';
import { ReadableStream as MiniflareReadableStream } from 'stream/web';
import { Response as MiniflareResponse } from '@miniflare/core';
import {
Expand Down Expand Up @@ -106,7 +107,15 @@ async function startServer(endpoint = '') {
});
const server = await mf.startServer();
const port = (server.address() as any).port;
const url = `http://localhost:${port}${endpoint}`;

const trimSlashes = (path: string): string => {
path = path.startsWith('/') ? path.slice(1) : path;
path = path.endsWith('/') ? path.slice(0, -1) : path;

return path;
};
const path = trimSlashes(endpoint);
const url = `http://localhost:${port}${path && `/${path}`}`;

const client = createTRPCProxyClient<typeof router>({
links: [httpBatchLink({ url, fetch: fetch as any })],
Expand Down Expand Up @@ -239,67 +248,23 @@ describe('with default server', () => {
});
});

// https://github.com/trpc/trpc/pull/4893
test('with / endpoint', async () => {
const custom = await startServer('/');
expect(
await custom.client.hello.query({
who: 'test',
}),
).toMatchInlineSnapshot(`
Object {
"text": "hello test",
}
`);

expect(await custom.client.hello.query()).toMatchInlineSnapshot(`
Object {
"text": "hello world",
}
`);
await custom.close();
});

// https://github.com/trpc/trpc/pull/4893
// endpoint with trailing slash
test('with /trpc/ endpoint', async () => {
const custom = await startServer('/trpc/');
expect(
await custom.client.hello.query({
who: 'test',
}),
).toMatchInlineSnapshot(`
Object {
"text": "hello test",
}
`);

expect(await custom.client.hello.query()).toMatchInlineSnapshot(`
Object {
"text": "hello world",
}
`);
await custom.close();
});

// https://github.com/trpc/trpc/pull/4893
// endpoint without trailing slash
test('with /trpc endpoint', async () => {
const custom = await startServer('/trpc');
test.each([
// https://github.com/trpc/trpc/pull/4893
'/',
'trpc',
/// https://github.com/trpc/trpc/issues/5089
'trpc/',
'/trpc/',
'/x/y/z',
])('with "%s" endpoint', async (endpoint) => {
const custom = await startServer(endpoint);
expect(
await custom.client.hello.query({
who: 'test',
}),
).toMatchInlineSnapshot(`
Object {
"text": "hello test",
}
`);
).toEqual({
text: 'hello test',
});

expect(await custom.client.hello.query()).toMatchInlineSnapshot(`
Object {
"text": "hello world",
}
`);
await custom.close();
});

3 comments on commit 578a394

@vercel
Copy link

@vercel vercel bot commented on 578a394 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

www – ./www

www-git-main-trpc.vercel.app
www-trpc.vercel.app
www.trpc.io
trpc.io
alpha.trpc.io
beta.trpc.io

@vercel
Copy link

@vercel vercel bot commented on 578a394 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

next-prisma-starter – ./examples/next-prisma-starter

nextjs.trpc.io
next-prisma-starter-git-main-trpc.vercel.app
next-prisma-starter-trpc.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 578a394 Nov 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

og-image – ./www/og-image

og-image-three-neon.vercel.app
og-image-git-main-trpc.vercel.app
og-image-trpc.vercel.app
og-image.trpc.io

Please sign in to comment.