Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "feat: support variadic middleware for routes" #87

Merged
merged 1 commit into from
Nov 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 5 additions & 13 deletions src/koa-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,6 @@ export type EndpointImplementation<
context: ContextOfEndpoint<RouteName, Request, RouterType>,
) => Response | Promise<Response>;

export type OneSchemaRouterMiddleware<Context> = (
context: Context,
next: () => Promise<any>,
) => any | Promise<any>;

export const implementRoute = <
Route extends string,
Request,
Expand All @@ -108,9 +103,6 @@ export const implementRoute = <
route: Route,
router: R,
parse: (ctx: ContextOfEndpoint<Route, Request, R>, data: unknown) => Request,
middlewares: OneSchemaRouterMiddleware<
ContextOfEndpoint<Route, Request, R>
>[],
implementation: EndpointImplementation<Route, Request, Response, R>,
) => {
// Separate method and path. e.g. 'POST my/route' => ['POST', 'my/route']
Expand Down Expand Up @@ -171,19 +163,19 @@ export const implementRoute = <
// Register the route + handler on the router.
switch (method) {
case 'POST':
router.post(path, ...middlewares, handler);
router.post(path, handler);
break;
case 'GET':
router.get(path, ...middlewares, handler);
router.get(path, handler);
break;
case 'PUT':
router.put(path, ...middlewares, handler);
router.put(path, handler);
break;
case 'PATCH':
router.patch(path, ...middlewares, handler);
router.patch(path, handler);
break;
case 'DELETE':
router.delete(path, ...middlewares, handler);
router.delete(path, handler);
break;
default:
throw new Error(`Unsupported method detected: ${route}`);
Expand Down
1 change: 0 additions & 1 deletion src/koa.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ export const implementSchema = <
data,
});
},
[],
routeHandler,
);
}
Expand Down
106 changes: 3 additions & 103 deletions src/router.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,11 +410,10 @@ describe('output validation', () => {
request: z.object({}),
response: z.object({ message: z.string() }),
})
.implement(
`${method} /items`,
.implement(`${method} /items`, () => ({
// @ts-expect-error Intentionally writing incorrect TS here
() => ({ message: 123 }),
),
message: 123,
})),
);

const { status } = await client.request({
Expand Down Expand Up @@ -510,105 +509,6 @@ describe('implementations', () => {
});
});

describe('using middleware', () => {
test('type errors are caught when using middleware', () => {
type CustomState = { message: string };

setup(() =>
OneSchemaRouter.create({
using: new Router<CustomState>(),
introspection: undefined,
})
.declare({
name: 'putItem',
route: 'PUT /items/:id',
request: z.object({ message: z.string() }),
response: z.object({ id: z.string(), message: z.string() }),
})
.implement(
'PUT /items/:id',
// @ts-expect-error
async (ctx, next) => {
ctx.state.message = ctx.request.body.message + '-response';
await next();
},
// We're leaving out the id value here, which should cause the TS error.
(ctx) => ({ message: ctx.state.message }),
)
.implement(
'PUT /items/:id',
async (ctx, next) => {
ctx.params.id;

ctx.request.body.message;

// @ts-expect-error The params should be well-typed.
ctx.params.bogus;

// @ts-expect-error The body should be well-typed.
ctx.request.body.bogus;

await next();
},
(ctx) => ({ id: 'test-id', message: ctx.state.message }),
)
.implement(
'PUT /items/:id',
(ctx, next) => {
// This call implicitly tests that `message` is a string.
ctx.state.message.endsWith('');

// @ts-expect-error The state should be well-typed.
ctx.state.bogus;

return next();
},
(ctx) => ({ id: 'test-id', message: ctx.state.message }),
),
);
});

test('middlewares are actually executed', async () => {
const mock = jest.fn();
const { typed: client } = setup((router) =>
router
.declare({
name: 'putItem',
route: 'PUT /items/:id',
request: z.object({ message: z.string() }),
response: z.object({ id: z.string(), message: z.string() }),
})
.implement(
'PUT /items/:id',
async (ctx, next) => {
mock('middleware 1', ctx.state.message);
ctx.state.message = 'message 1';
await next();
},
(ctx, next) => {
mock('middleware 2', ctx.state.message);
ctx.state.message = 'message 2';
return next();
},
(ctx) => ({ id: ctx.params.id, message: ctx.state.message }),
),
);

const { status, data } = await client.putItem({
id: 'test-id-bleh',
message: 'test-message',
});

expect(status).toStrictEqual(200);
expect(data).toStrictEqual({ id: 'test-id-bleh', message: 'message 2' });

expect(mock.mock.calls).toEqual([
['middleware 1', undefined],
['middleware 2', 'message 1'],
]);
});
});

describe('introspection', () => {
test('introspecting + generating a client', async () => {
const { client } = serve(
Expand Down
27 changes: 7 additions & 20 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import { fromZodError } from 'zod-validation-error';
import zodToJsonSchema from 'zod-to-json-schema';
import compose = require('koa-compose');
import {
ContextOfEndpoint,
EndpointImplementation,
implementRoute,
OneSchemaRouterMiddleware,
PathParamsOf,
} from './koa-utils';
import { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
Expand Down Expand Up @@ -99,24 +97,15 @@ export class OneSchemaRouter<

implement<Route extends keyof Schema & string>(
route: Route,
...middlewares: [
...OneSchemaRouterMiddleware<
ContextOfEndpoint<Route, z.output<Schema[Route]['request']>, R>
>[],
EndpointImplementation<
Route,
z.output<Schema[Route]['request']>,
z.infer<Schema[Route]['response']>,
R
>,
]
): this {
implementation: EndpointImplementation<
Route,
z.output<Schema[Route]['request']>,
z.infer<Schema[Route]['response']>,
R
>,
) {
const endpoint = this.schema[route];

const mws = middlewares.slice(0, -1) as any[];

const implementation = middlewares.at(-1) as any;

implementRoute(
route,
this.router,
Expand All @@ -130,8 +119,6 @@ export class OneSchemaRouter<
}
return res.data;
},
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
mws,
async (ctx) => {
const result = await implementation(ctx);
const res = endpoint.response.safeParse(result);
Expand Down