Skip to content

Commit

Permalink
Feat: Describing alternative or actual placement of the input security (
Browse files Browse the repository at this point in the history
  • Loading branch information
RobinTail authored Dec 26, 2023
1 parent 01ff071 commit 173ea0f
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 8 deletions.
2 changes: 2 additions & 0 deletions example/example.documentation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,8 @@ components:
type: apiKey
in: query
name: key
x-in-actual: body
description: key MUST be supplied within the request body instead of query
APIKEY_2:
type: apiKey
in: header
Expand Down
33 changes: 26 additions & 7 deletions src/documentation-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ export const depictResponse = ({

type SecurityHelper<K extends Security["type"]> = (
security: Security & { type: K },
inputSources?: InputSource[],
) => SecuritySchemeObject;

const depictBasicSecurity: SecurityHelper<"basic"> = () => ({
Expand All @@ -932,12 +933,26 @@ const depictBearerSecurity: SecurityHelper<"bearer"> = ({
}
return result;
};
// @todo add description on actual input placement
const depictInputSecurity: SecurityHelper<"input"> = ({ name }) => ({
type: "apiKey",
in: "query", // body is not supported yet, https://swagger.io/docs/specification/authentication/api-keys/
name,
});
const depictInputSecurity: SecurityHelper<"input"> = (
{ name },
inputSources,
) => {
const result: SecuritySchemeObject = {
type: "apiKey",
in: "query",
name,
};
if (inputSources?.includes("body")) {
if (inputSources?.includes("query")) {
result["x-in-alternative"] = "body";
result.description = `${name} CAN also be supplied within the request body`;
} else {
result["x-in-actual"] = "body";
result.description = `${name} MUST be supplied within the request body instead of query`;
}
}
return result;
};
const depictHeaderSecurity: SecurityHelper<"header"> = ({ name }) => ({
type: "apiKey",
in: "header",
Expand Down Expand Up @@ -970,6 +985,7 @@ const depictOAuth2Security: SecurityHelper<"oauth2"> = ({ flows = {} }) => ({

export const depictSecurity = (
container: LogicalContainer<Security>,
inputSources?: InputSource[],
): LogicalContainer<SecuritySchemeObject> => {
const methods: { [K in Security["type"]]: SecurityHelper<K> } = {
basic: depictBasicSecurity,
Expand All @@ -981,7 +997,10 @@ export const depictSecurity = (
oauth2: depictOAuth2Security,
};
return mapLogicalContainer(container, (security) =>
(methods[security.type] as SecurityHelper<typeof security.type>)(security),
(methods[security.type] as SecurityHelper<typeof security.type>)(
security,
inputSources,
),
);
};

Expand Down
2 changes: 1 addition & 1 deletion src/documentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ export class Documentation extends OpenApiBuilder {
}
const securityRefs = depictSecurityRefs(
mapLogicalContainer(
depictSecurity(endpoint.getSecurity()),
depictSecurity(endpoint.getSecurity(), inputSources),
(securitySchema) => {
const name = this.ensureUniqSecuritySchemaName(securitySchema);
const scopes = ["oauth2", "openIdConnect"].includes(
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/__snapshots__/documentation-helpers.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,26 @@ exports[`Documentation helpers > depictSecurity() > should handle undefined flow
}
`;

exports[`Documentation helpers > depictSecurity() > should inform on 'actual' placement of the input security parameter 1`] = `
{
"description": "key MUST be supplied within the request body instead of query",
"in": "query",
"name": "key",
"type": "apiKey",
"x-in-actual": "body",
}
`;

exports[`Documentation helpers > depictSecurity() > should inform on 'alternative' placement of the input security parameter 1`] = `
{
"description": "key CAN also be supplied within the request body",
"in": "query",
"name": "key",
"type": "apiKey",
"x-in-alternative": "body",
}
`;

exports[`Documentation helpers > depictSecurityRefs() > should handle LogicalAnd 1`] = `
[
{
Expand Down
4 changes: 4 additions & 0 deletions tests/unit/__snapshots__/documentation.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1685,6 +1685,8 @@ components:
type: apiKey
in: query
name: key
x-in-actual: body
description: key MUST be supplied within the request body instead of query
APIKEY_2:
type: apiKey
in: header
Expand Down Expand Up @@ -2222,6 +2224,8 @@ components:
type: apiKey
in: query
name: key
x-in-actual: body
description: key MUST be supplied within the request body instead of query
APIKEY_2:
type: apiKey
in: header
Expand Down
14 changes: 14 additions & 0 deletions tests/unit/documentation-helpers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1027,6 +1027,20 @@ describe("Documentation helpers", () => {
}),
).toMatchSnapshot();
});
test.each([
{ variant: "alternative", inputSources: ["query", "body"] as const },
{ variant: "actual", inputSources: ["body", "files"] as const },
])(
`should inform on $variant placement of the input security parameter`,
({ inputSources }) => {
expect(
depictSecurity(
{ type: "input", name: "key" },
Array.from(inputSources),
),
).toMatchSnapshot();
},
);
test("should handle OpenID and OAuth2 Securities", () => {
expect(
depictSecurity({
Expand Down

0 comments on commit 173ea0f

Please sign in to comment.