Skip to content

Commit

Permalink
feat: impl security path
Browse files Browse the repository at this point in the history
  • Loading branch information
JuMastro committed Aug 8, 2023
1 parent d1eab87 commit c5284ea
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 2 deletions.
19 changes: 18 additions & 1 deletion src/generator/paths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,31 @@ export const getOpenApiPathsObject = (

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

let securityNames: string[] | undefined;

if (protect) {
if (Array.isArray(protect)) {
const unexists = protect.filter((name) => !securitySchemeNames.includes(name));
if (unexists.length) {
throw new TRPCError({
message: `"${unexists.join(',')}" must exists in "securitySchemes"`,
code: 'INTERNAL_SERVER_ERROR',
});
}
securityNames = protect;
} else {
securityNames = securitySchemeNames;
}
}

pathsObject[path] = {
...pathsObject[path],
[httpMethod]: {
operationId: procedurePath.replace(/\./g, '-'),
summary,
description,
tags: tags,
security: protect ? securitySchemeNames.map((name) => ({ [name]: [] })) : undefined,
security: securityNames?.map((name) => ({ [name]: [] })),
...(acceptsRequestBody(method)
? {
requestBody: getRequestBodyObject(
Expand Down
2 changes: 1 addition & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type OpenApiMeta<TMeta = TRPCMeta> = TMeta & {
path: `/${string}`;
summary?: string;
description?: string;
protect?: boolean;
protect?: boolean | string[];
tags?: string[];
headers?: (OpenAPIV3.ParameterBaseObject & { name: string; in?: 'header' })[];
contentTypes?: OpenApiContentType[];
Expand Down
48 changes: 48 additions & 0 deletions test/generator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -849,6 +849,54 @@ describe('generator', () => {
]);
});

test('with defined security', () => {
const appRouter = t.router({
protectedEndpoint: t.procedure
.meta({
openapi: { method: 'POST', path: '/secure/endpoint', protect: ['a', 'b'] },
})
.input(z.object({ name: z.string() }))
.output(z.object({ name: z.string() }))
.query(({ input }) => ({ name: input.name })),
});

const openApiDocument = generateOpenApiDocument(appRouter, {
...defaultDocOpts,
securitySchemes: {
a: {
type: 'apiKey',
name: 'a',
in: 'header',
},
b: {
type: 'apiKey',
name: 'b',
in: 'header',
},
},
});

expect(openApiSchemaValidator.validate(openApiDocument).errors).toEqual([]);
expect(openApiDocument.paths['/secure/endpoint']!.post!.security).toEqual([
{ a: [] },
{ b: [] },
]);
});

test('with missing securityScheme', () => {
const appRouter = t.router({
protectedEndpoint: t.procedure
.meta({ openapi: { method: 'POST', path: '/secure/endpoint', protect: ['a', 'b'] } })
.input(z.object({ name: z.string() }))
.output(z.object({ name: z.string() }))
.query(({ input }) => ({ name: input.name })),
});

expect(() => {
generateOpenApiDocument(appRouter, defaultDocOpts);
}).toThrowError('[query.protectedEndpoint] - "a,b" must exists in "securitySchemes"');
});

test('with schema descriptions', () => {
const appRouter = t.router({
createUser: t.procedure
Expand Down

0 comments on commit c5284ea

Please sign in to comment.