Skip to content
This repository was archived by the owner on Nov 19, 2024. It is now read-only.

Commit c5284ea

Browse files
committed
feat: impl security path
1 parent d1eab87 commit c5284ea

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

src/generator/paths.ts

+18-1
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,31 @@ export const getOpenApiPathsObject = (
5656

5757
const { inputParser, outputParser } = getInputOutputParsers(procedure);
5858

59+
let securityNames: string[] | undefined;
60+
61+
if (protect) {
62+
if (Array.isArray(protect)) {
63+
const unexists = protect.filter((name) => !securitySchemeNames.includes(name));
64+
if (unexists.length) {
65+
throw new TRPCError({
66+
message: `"${unexists.join(',')}" must exists in "securitySchemes"`,
67+
code: 'INTERNAL_SERVER_ERROR',
68+
});
69+
}
70+
securityNames = protect;
71+
} else {
72+
securityNames = securitySchemeNames;
73+
}
74+
}
75+
5976
pathsObject[path] = {
6077
...pathsObject[path],
6178
[httpMethod]: {
6279
operationId: procedurePath.replace(/\./g, '-'),
6380
summary,
6481
description,
6582
tags: tags,
66-
security: protect ? securitySchemeNames.map((name) => ({ [name]: [] })) : undefined,
83+
security: securityNames?.map((name) => ({ [name]: [] })),
6784
...(acceptsRequestBody(method)
6885
? {
6986
requestBody: getRequestBodyObject(

src/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type OpenApiMeta<TMeta = TRPCMeta> = TMeta & {
2222
path: `/${string}`;
2323
summary?: string;
2424
description?: string;
25-
protect?: boolean;
25+
protect?: boolean | string[];
2626
tags?: string[];
2727
headers?: (OpenAPIV3.ParameterBaseObject & { name: string; in?: 'header' })[];
2828
contentTypes?: OpenApiContentType[];

test/generator.test.ts

+48
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,54 @@ describe('generator', () => {
849849
]);
850850
});
851851

852+
test('with defined security', () => {
853+
const appRouter = t.router({
854+
protectedEndpoint: t.procedure
855+
.meta({
856+
openapi: { method: 'POST', path: '/secure/endpoint', protect: ['a', 'b'] },
857+
})
858+
.input(z.object({ name: z.string() }))
859+
.output(z.object({ name: z.string() }))
860+
.query(({ input }) => ({ name: input.name })),
861+
});
862+
863+
const openApiDocument = generateOpenApiDocument(appRouter, {
864+
...defaultDocOpts,
865+
securitySchemes: {
866+
a: {
867+
type: 'apiKey',
868+
name: 'a',
869+
in: 'header',
870+
},
871+
b: {
872+
type: 'apiKey',
873+
name: 'b',
874+
in: 'header',
875+
},
876+
},
877+
});
878+
879+
expect(openApiSchemaValidator.validate(openApiDocument).errors).toEqual([]);
880+
expect(openApiDocument.paths['/secure/endpoint']!.post!.security).toEqual([
881+
{ a: [] },
882+
{ b: [] },
883+
]);
884+
});
885+
886+
test('with missing securityScheme', () => {
887+
const appRouter = t.router({
888+
protectedEndpoint: t.procedure
889+
.meta({ openapi: { method: 'POST', path: '/secure/endpoint', protect: ['a', 'b'] } })
890+
.input(z.object({ name: z.string() }))
891+
.output(z.object({ name: z.string() }))
892+
.query(({ input }) => ({ name: input.name })),
893+
});
894+
895+
expect(() => {
896+
generateOpenApiDocument(appRouter, defaultDocOpts);
897+
}).toThrowError('[query.protectedEndpoint] - "a,b" must exists in "securitySchemes"');
898+
});
899+
852900
test('with schema descriptions', () => {
853901
const appRouter = t.router({
854902
createUser: t.procedure

0 commit comments

Comments
 (0)