Skip to content

Commit

Permalink
fix(schema): allow declaring Header response without defined value
Browse files Browse the repository at this point in the history
  • Loading branch information
Romakita committed Mar 26, 2024
1 parent ca0f7f5 commit b4bd6d6
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 5 deletions.
17 changes: 17 additions & 0 deletions packages/platform/common/src/utils/setResponseHeaders.spec.ts
Expand Up @@ -23,6 +23,23 @@ describe("setResponseHeaders", () => {
expect(ctx.response.getHeaders()).toEqual({"x-request-id": "id", "x-header": "test"});
expect(ctx.response.statusCode).toEqual(200);
});
it("should not set headers automatically if the value isn't declared", async () => {
class Test {
@Get("/")
@Returns(200).Header("x-header")
test() {}
}

const ctx = PlatformTest.createRequestContext();
ctx.endpoint = EndpointMetadata.get(Test, "test");

// WHEN
await setResponseHeaders(ctx);

// THEN
expect(ctx.response.getHeaders()).toEqual({"x-request-id": "id"});
expect(ctx.response.statusCode).toEqual(200);
});

it("should redirect", async () => {
class Test {
Expand Down
2 changes: 1 addition & 1 deletion packages/platform/common/src/utils/setResponseHeaders.ts
Expand Up @@ -20,7 +20,7 @@ export function setResponseHeaders(ctx: PlatformContext) {
const headers = operation.getHeadersOf(statusCode);

Object.entries(headers).forEach(([key, item]: any[]) => {
if (!response.get(key)) {
if (!response.get(key) && item.example !== undefined) {
response.setHeader(key, String(item.example));
}
});
Expand Down
Expand Up @@ -27,6 +27,26 @@ describe("setResponseHeaders", () => {
expect(ctx.response.setHeaders).toHaveBeenCalledWith({"x-header": "test"});
expect(ctx.response.status).toHaveBeenCalledWith(200);
});
it("should not set headers automatically", async () => {
class Test {
@Get("/")
@Returns(200).Header("x-header")
test() {}
}

const ctx = createServerlessContext({
endpoint: JsonEntityStore.fromMethod(Test, "test")
});

jest.spyOn(ctx.response, "setHeaders");
jest.spyOn(ctx.response, "status");
// WHEN
await setResponseHeaders(ctx);

// THEN
expect(ctx.response.setHeaders).toHaveBeenCalledWith({});
expect(ctx.response.status).toHaveBeenCalledWith(200);
});
it("should redirect with 301", async () => {
class Test {
@Get("/")
Expand Down
Expand Up @@ -5,10 +5,17 @@ import {HeaderValue} from "../domain/ServerlessResponse";
function mergeHeaders(specHeaders: Record<string, JsonHeader & {example: string}>, headers: Record<string, HeaderValue>) {
return Object.entries(specHeaders).reduce((headers, [key, item]) => {
key = key.toLowerCase();
return {
...headers,
[key]: headers[key] === undefined ? String(item.example) : headers[key]
};

const value = headers[key] === undefined ? item.example : headers[key];

if (value !== undefined) {
return {
...headers,
[key]: String(value)
};
}

return headers;
}, headers);
}

Expand Down
63 changes: 63 additions & 0 deletions packages/specs/schema/src/decorators/common/const.spec.ts
@@ -1,5 +1,9 @@
import {SpecTypes} from "../../domain/SpecTypes";
import {getJsonSchema} from "../../utils/getJsonSchema";
import {getSpec} from "../../utils/getSpec";
import {In} from "../operations/in";
import {OperationPath} from "../operations/operationPath";
import {Path} from "../operations/path";
import {Const} from "./const";

describe("@Const", () => {
Expand Down Expand Up @@ -30,4 +34,63 @@ describe("@Const", () => {
type: "object"
});
});
it("should declare prop (spec)", () => {
// WHEN
class Model {
@Const("10")
num: string = "10";
}

@Path("/")
class MyController {
@OperationPath("POST", "/")
get(@In("body") payload: Model) {}
}

const spec = getSpec(MyController, {specType: SpecTypes.OPENAPI});

expect(spec).toEqual({
components: {
schemas: {
Model: {
properties: {
num: {
type: "string"
}
},
type: "object"
}
}
},
paths: {
"/": {
post: {
operationId: "myControllerGet",
parameters: [],
requestBody: {
content: {
"application/json": {
schema: {
$ref: "#/components/schemas/Model"
}
}
},
required: false
},
responses: {
"200": {
description: "Success"
}
},
tags: ["MyController"]
}
}
},
tags: [
{
name: "MyController"
}
]
});
});
});
46 changes: 46 additions & 0 deletions packages/specs/schema/src/decorators/operations/header.spec.ts
Expand Up @@ -50,6 +50,52 @@ describe("Header", () => {
});
});
});
describe("with one param as string", () => {
it("should set Header", () => {
class MyController {
@Header("x-header")
@OperationPath("GET", "/")
test() {}
}

const spec = getSpec(MyController, {specType: SpecTypes.OPENAPI});

expect(spec).toEqual({
paths: {
"/": {
get: {
operationId: "myControllerTest",
parameters: [],
responses: {
"200": {
content: {
"*/*": {
schema: {
type: "object"
}
}
},
headers: {
"x-header": {
schema: {
type: "string"
}
}
}
}
},
tags: ["MyController"]
}
}
},
tags: [
{
name: "MyController"
}
]
});
});
});
describe("with two params has object", () => {
it("should set Header", () => {
class MyController {
Expand Down
4 changes: 4 additions & 0 deletions packages/specs/schema/src/decorators/operations/header.ts
@@ -1,3 +1,4 @@
import {isString} from "@tsed/core";
import {JsonHeader, JsonHeaders} from "../../interfaces/JsonOpenSpec";
import {Returns} from "./returns";

Expand Down Expand Up @@ -52,6 +53,9 @@ export function Header(headers: string | number | JsonHeaders, value?: string |
if (value !== undefined) {
headers = {[headers as string]: value};
}
if (value === undefined && isString(headers)) {
headers = {[headers as string]: {type: "string"}};
}

return Returns().Headers(headers as JsonHeaders);
}

0 comments on commit b4bd6d6

Please sign in to comment.