Skip to content

WIP: Adding requestBodies transform support #474

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

Merged
merged 2 commits into from
Mar 2, 2021
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
7 changes: 2 additions & 5 deletions src/transform/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { comment } from "../utils";
import { transformHeaderObjMap } from "./headers";
import { transformOperationObj } from "./operation";
import { transformPathsObj } from "./paths";
import { transformResponsesObj } from "./responses";
import { transformResponsesObj, transformRequestBodies } from "./responses";
import { transformSchemaObjMap } from "./schema";

interface TransformOptions {
Expand Down Expand Up @@ -89,10 +89,7 @@ export function transformAll(schema: any, { version, rawSchema }: TransformOptio

// #/components/requestBodies
if (schema.components.requestBodies) {
const required = Object.keys(schema.components.requestBodies);
output += ` requestBodies: {\n ${transformSchemaObjMap(schema.components.requestBodies, {
required,
})}\n }\n`;
output += ` requestBodies: {\n ${transformRequestBodies(schema.components.requestBodies)}\n }\n`;
}

// #/components/headers
Expand Down
36 changes: 23 additions & 13 deletions src/transform/operation.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { OperationObject, ParameterObject } from "../types";
import { OperationObject, ParameterObject, RequestBody } from "../types";
import { comment, isRef, transformRef } from "../utils";
import { transformParametersArray } from "./parameters";
import { transformResponsesObj } from "./responses";
Expand All @@ -22,21 +22,31 @@ export function transformOperationObj(
if (isRef(operation.requestBody)) {
output += ` requestBody: ${transformRef(operation.requestBody.$ref)};\n`;
} else {
const { description, content } = operation.requestBody;
if (operation.requestBody.description) output += comment(operation.requestBody.description);

if (description) output += comment(description);
output += ` requestBody: {\n`; // open requestBody
output += ` ${transformRequestBodyObj(operation.requestBody)}`;
output += ` }\n`; // close requestBody
}
}

if (content && Object.keys(content).length) {
output += ` requestBody: {\n content: {\n`; // open requestBody
return output;
}

Object.entries(content).forEach(([k, v]) => {
output += ` "${k}": ${transformSchemaObj(v.schema)};\n`;
});
output += ` }\n }\n`; // close requestBody
} else {
output += ` requestBody: unknown;\n`;
}
}
export function transformRequestBodyObj(requestBody: RequestBody) {
let output = "";

const { content } = requestBody;

if (content && Object.keys(content).length) {
output += ` content: {\n`; // open content

Object.entries(content).forEach(([k, v]) => {
output += ` "${k}": ${transformSchemaObj(v.schema)};\n`;
});
output += ` }\n`; // close content
} else {
output += ` unknown;\n`;
}

return output;
Expand Down
15 changes: 15 additions & 0 deletions src/transform/responses.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { comment, transformRef } from "../utils";
import { transformHeaderObjMap } from "./headers";
import { transformSchemaObj } from "./schema";
import { transformRequestBodyObj } from "./operation";
import { RequestBody } from "../types";

const resType = (res: string | number) => (res === 204 || (res >= 300 && res < 400) ? "never" : "unknown");

Expand Down Expand Up @@ -49,3 +51,16 @@ export function transformResponsesObj(responsesObj: Record<string, any>): string
});
return output;
}

export function transformRequestBodies(requestBodies: Record<string, RequestBody>) {
let output = "";

Object.entries(requestBodies).forEach(([bodyName, requestBody]) => {
if (requestBody && requestBody.description) output += ` ${comment(requestBody.description)}`;
output += ` ${bodyName}: {`;
output += ` ${transformRequestBodyObj(requestBody)}`;
output += ` }\n`;
});

return output;
}
37 changes: 37 additions & 0 deletions tests/operation.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import prettier from "prettier";
import { transformOperationObj } from "../src/transform/operation";
import { transformRequestBodies } from "../src/transform/responses";

describe("requestBody", () => {
it("basic", () => {
Expand Down Expand Up @@ -31,3 +33,38 @@ describe("requestBody", () => {
).toBe(`requestBody: components["requestBodies"]["Request"];`);
});
});

describe("requestBodies", () => {
const format = (source: string) => prettier.format(source, { parser: "typescript" });
Copy link
Contributor

@drwpow drwpow Mar 2, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably remember the previous versions of the test. Here’s some extra context for why it‘s not in the unit tests now.

Prettier saves a lot of code managing indents, quotation style, etc. By just running Prettier at the end, this library can do less formatting, and only has to render valid (albeit messy) TypeScript. But recently I noticed that this library wasn’t generating syntax correctly in places, and Prettier sometimes would format incorrectly. So I wanted to write more tests without Prettier to make sure the generated code was valid TS, and Prettier wasn’t hiding any issues. But that comes with drawbacks, obviously—it’s annoying to write & test unformatted code.

Anyway, I’m fine having Prettier in some tests, and it’s fine here! But in most places it’s been intentionally left out.


it("basic", () => {
const output = transformRequestBodies({
Pet: {
description: "Pet request body",
content: {
"application/json": {
schema: {
type: "object",
properties: {
test: { type: "string" },
},
},
},
},
},
}).trim();

expect(format(`type requestBodies = {${output}}`)).toBe(
format(`type requestBodies = {
/** Pet request body */
Pet: {
content: {
"application/json": {
test?: string;
};
};
};
};`)
);
});
});
13 changes: 11 additions & 2 deletions tests/v3/expected/petstore-openapitools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,18 @@ export interface components {
};
requestBodies: {
/** List of user object */
UserArray: { [key: string]: any };
UserArray: {
content: {
"application/json": components["schemas"]["User"][];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test!

};
};
/** Pet object that needs to be added to the store */
Pet: { [key: string]: any };
Pet: {
content: {
"application/json": components["schemas"]["Pet"];
"application/xml": components["schemas"]["Pet"];
};
};
};
}

Expand Down