Skip to content

Commit

Permalink
chore: allow reading from both YAML and JSON; refactor for preparatio…
Browse files Browse the repository at this point in the history
…n on parsing multipart/form-data (#106)
  • Loading branch information
imballinst authored Dec 12, 2023
1 parent ff8af0a commit 56f7ea6
Show file tree
Hide file tree
Showing 104 changed files with 1,789 additions and 1,524 deletions.
9 changes: 9 additions & 0 deletions .changeset/gorgeous-laws-hide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@oas-typescript/express': patch
'@oas-typescript/shared-cli-http-server': patch
'@oas-typescript/axios': patch
'@oas-typescript/koa': patch
'@oas-typescript/shared': patch
---

chore: allow reading from both YAML and JSON; refactor for preparation on parsing multipart/form-data
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified .yarn/install-state.gz
Binary file not shown.
11 changes: 7 additions & 4 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
nodeLinker: pnpm

packageExtensions:
"@koa/bodyparser@*":
'@koa/bodyparser@*':
peerDependencies:
koa: ^2.14.2
"@pnpm/npm-resolver@*":
'@pnpm/npm-resolver@*':
dependencies:
"@pnpm/logger": ^5.0.0
'@pnpm/logger': ^5.0.0
'fix-esm@*':
dependencies:
'multer': '*'

plugins:
- path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
spec: "@yarnpkg/plugin-workspace-tools"
spec: '@yarnpkg/plugin-workspace-tools'

yarnPath: .yarn/releases/yarn-3.6.4.cjs
4 changes: 3 additions & 1 deletion docs/docs/nodejs-server-stubs/01-concepts.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# Usage

In the previous section, you have learned how to generate the server stubs. The following is the file tree result if you are generating the server stubs of the [slightly adjusted Pet Store OpenAPI Specification 3.0](https://github.com/imballinst/oas-typescript/blob/main/packages/shared/src/openapi/api.json).
In the previous section, you have learned how to generate the server stubs. The following is the file tree result if you are generating the server stubs of the [slightly adjusted Pet Store OpenAPI Specification 3.0](https://github.com/imballinst/oas-typescript/blob/main/packages/shared/src/openapi/api.yaml).

```
generated
Expand Down Expand Up @@ -53,6 +53,7 @@ The security middleware is optional, because it's only required if there are end
The default security middleware looks like this.

<!--SNIPSTART middleware-helpers-vanilla-->

```ts
// Base class of MiddlewareHelpers.
export class MiddlewareHelpers {
Expand All @@ -77,6 +78,7 @@ export class MiddlewareHelpers {
}
}
```

<!--SNIPEND-->

The function receives `headers` and `securityObject`, the former comes from request whereas the latter comes from the OpenAPI specification. The function returns a resolved Promise (if validation is successful) and a rejected Promise (if validation fails). A modified security middleware helper looks like this:
Expand Down

This file was deleted.

56 changes: 51 additions & 5 deletions packages/oas-typescript-axios/generated-with-headers/pet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';
import { getQueryParameterString } from './utils/query.js';

import { ApiResponse } from './common';

// Schemas.
export const Category = z
.object({ id: z.number().int(), name: z.string() })
Expand Down Expand Up @@ -72,6 +70,26 @@ const UploadFileParams = z.object({
query: z.object({ additionalMetadata: z.string().optional() }),
body: z.instanceof(File)
});
const UploadFileResponse = z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough();
interface UploadFileResponse extends z.infer<typeof UploadFileResponse> {}

const UploadFileMultipartParams = z.object({
params: z.object({ petId: z.number().int() }),
query: z.object({ additionalMetadata: z.string().optional() }),
body: z
.object({ profileImage: z.instanceof(File) })
.partial()
.passthrough()
});
const UploadFileMultipartResponse = z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough();
interface UploadFileMultipartResponse
extends z.infer<typeof UploadFileMultipartResponse> {}

export function PetApi({
defaultAxiosRequestConfig
Expand Down Expand Up @@ -211,7 +229,7 @@ export function PetApi({
async function uploadFile(
fnParam: z.infer<typeof UploadFileParams>,
axiosConfig?: AxiosRequestConfig
): Promise<ApiResponse> {
): Promise<UploadFileResponse> {
let url = `/pet/${fnParam.params.petId}/uploadImage`;
url += getQueryParameterString(fnParam.query);

Expand All @@ -225,7 +243,34 @@ export function PetApi({
method: 'post'
};
const response = await axios(url, { ...config, data: fnParam.body });
return ApiResponse.parse(response.data);
return z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough()
.parse(response.data);
}
async function uploadFileMultipart(
fnParam: z.infer<typeof UploadFileMultipartParams>,
axiosConfig?: AxiosRequestConfig
): Promise<UploadFileMultipartResponse> {
let url = `/pet/${fnParam.params.petId}/uploadImageMultipart`;
url += getQueryParameterString(fnParam.query);

const config = {
...defaultAxiosRequestConfig,
...axiosConfig,
headers: {
...defaultAxiosRequestConfig?.headers,
...axiosConfig?.headers
},
method: 'post'
};
const response = await axios(url, { ...config, data: fnParam.body });
return z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough()
.parse(response.data);
}

return {
Expand All @@ -236,6 +281,7 @@ export function PetApi({
getPetById,
updatePetWithForm,
deletePet,
uploadFile
uploadFile,
uploadFileMultipart
};
}
2 changes: 0 additions & 2 deletions packages/oas-typescript-axios/generated-with-headers/store.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';

import { ApiResponse } from './common';

// Schemas.
export const Order = z
.object({
Expand Down
13 changes: 9 additions & 4 deletions packages/oas-typescript-axios/generated-with-headers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';
import { getQueryParameterString } from './utils/query.js';

import { ApiResponse } from './common';

// Schemas.
export const User = z
.object({
Expand All @@ -30,7 +28,10 @@ const LoginUserParams = z.object({
password: z.string().optional()
})
});
const LoginUserResponse = z.string();
const LoginUserResponse = z
.object({ status: z.string() })
.partial()
.passthrough();
interface LoginUserResponse extends z.infer<typeof LoginUserResponse> {}

const GetUserByNameParams = z.object({
Expand Down Expand Up @@ -104,7 +105,11 @@ export function UserApi({
method: 'get'
};
const response = await axios(url, config);
return z.string().parse(response.data);
return z
.object({ status: z.string() })
.partial()
.passthrough()
.parse(response.data);
}
async function logoutUser(axiosConfig?: AxiosRequestConfig): Promise<void> {
let url = `/user/logout`;
Expand Down
6 changes: 0 additions & 6 deletions packages/oas-typescript-axios/generated/common.ts

This file was deleted.

56 changes: 51 additions & 5 deletions packages/oas-typescript-axios/generated/pet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';
import { getQueryParameterString } from './utils/query.js';

import { ApiResponse } from './common';

// Schemas.
export const Category = z
.object({ id: z.number().int(), name: z.string() })
Expand Down Expand Up @@ -72,6 +70,26 @@ const UploadFileParams = z.object({
query: z.object({ additionalMetadata: z.string().optional() }),
body: z.instanceof(File)
});
const UploadFileResponse = z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough();
interface UploadFileResponse extends z.infer<typeof UploadFileResponse> {}

const UploadFileMultipartParams = z.object({
params: z.object({ petId: z.number().int() }),
query: z.object({ additionalMetadata: z.string().optional() }),
body: z
.object({ profileImage: z.instanceof(File) })
.partial()
.passthrough()
});
const UploadFileMultipartResponse = z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough();
interface UploadFileMultipartResponse
extends z.infer<typeof UploadFileMultipartResponse> {}

export function PetApi({
defaultAxiosRequestConfig
Expand Down Expand Up @@ -211,7 +229,7 @@ export function PetApi({
async function uploadFile(
fnParam: z.infer<typeof UploadFileParams>,
axiosConfig?: AxiosRequestConfig
): Promise<ApiResponse> {
): Promise<UploadFileResponse> {
let url = `/pet/${fnParam.params.petId}/uploadImage`;
url += getQueryParameterString(fnParam.query);

Expand All @@ -225,7 +243,34 @@ export function PetApi({
method: 'post'
};
const response = await axios(url, { ...config, data: fnParam.body });
return ApiResponse.parse(response.data);
return z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough()
.parse(response.data);
}
async function uploadFileMultipart(
fnParam: z.infer<typeof UploadFileMultipartParams>,
axiosConfig?: AxiosRequestConfig
): Promise<UploadFileMultipartResponse> {
let url = `/pet/${fnParam.params.petId}/uploadImageMultipart`;
url += getQueryParameterString(fnParam.query);

const config = {
...defaultAxiosRequestConfig,
...axiosConfig,
headers: {
...defaultAxiosRequestConfig?.headers,
...axiosConfig?.headers
},
method: 'post'
};
const response = await axios(url, { ...config, data: fnParam.body });
return z
.object({ code: z.number().int(), type: z.string(), message: z.string() })
.partial()
.passthrough()
.parse(response.data);
}

return {
Expand All @@ -236,6 +281,7 @@ export function PetApi({
getPetById,
updatePetWithForm,
deletePet,
uploadFile
uploadFile,
uploadFileMultipart
};
}
2 changes: 0 additions & 2 deletions packages/oas-typescript-axios/generated/store.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';

import { ApiResponse } from './common';

// Schemas.
export const Order = z
.object({
Expand Down
13 changes: 9 additions & 4 deletions packages/oas-typescript-axios/generated/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { z } from 'zod';
import axios, { AxiosRequestConfig } from 'axios';
import { getQueryParameterString } from './utils/query.js';

import { ApiResponse } from './common';

// Schemas.
export const User = z
.object({
Expand All @@ -30,7 +28,10 @@ const LoginUserParams = z.object({
password: z.string().optional()
})
});
const LoginUserResponse = z.string();
const LoginUserResponse = z
.object({ status: z.string() })
.partial()
.passthrough();
interface LoginUserResponse extends z.infer<typeof LoginUserResponse> {}

const GetUserByNameParams = z.object({
Expand Down Expand Up @@ -104,7 +105,11 @@ export function UserApi({
method: 'get'
};
const response = await axios(url, config);
return z.string().parse(response.data);
return z
.object({ status: z.string() })
.partial()
.passthrough()
.parse(response.data);
}
async function logoutUser(axiosConfig?: AxiosRequestConfig): Promise<void> {
let url = `/user/logout`;
Expand Down
7 changes: 4 additions & 3 deletions packages/oas-typescript-axios/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
},
"scripts": {
"gen": "yarn build:entry && yarn gen:build && yarn gen:build:headers",
"gen:build": "node --experimental-modules cli.js generate ../shared/src/openapi/api.json --output generated",
"gen:build:headers": "node --experimental-modules cli.js generate ../shared/src/openapi/api.json --output generated-with-headers --with-headers",
"gen:build": "node --experimental-modules cli.js generate ../shared/src/openapi/api.yaml --output generated",
"gen:build:headers": "node --experimental-modules cli.js generate ../shared/src/openapi/api.yaml --output generated-with-headers --with-headers",
"gen:templates": "node --loader ts-node/esm scripts/fill-templates.ts",
"gen:all": "yarn gen:templates && yarn gen",
"build": "yarn test:run && yarn gen:templates && yarn build:entry",
Expand All @@ -25,7 +25,8 @@
"dependencies": {
"meow": "12.0.1",
"openapi-zod-client": "1.10.0",
"title-case": "3.0.3"
"title-case": "3.0.3",
"yaml": "2.3.4"
},
"peerDependencies": {
"axios": ">=1.0.0"
Expand Down
9 changes: 6 additions & 3 deletions packages/oas-typescript-axios/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env node
import { OpenAPIV3 } from 'openapi-types';
import { parse as parseYAML } from 'yaml';
import { tmpdir } from 'os';
import { generateZodClientFromOpenAPI } from 'openapi-zod-client';
import fs from 'fs/promises';
Expand Down Expand Up @@ -81,9 +82,11 @@ async function main() {
]);

// Start the process.
const document: OpenAPIV3.Document = JSON.parse(
await fs.readFile(input, 'utf-8')
);
const fileContent = await fs.readFile(input, 'utf-8');
const document: OpenAPIV3.Document =
path.extname(input) === '.json'
? JSON.parse(fileContent)
: parseYAML(fileContent);

await generateZodClientFromOpenAPI({
openApiDoc: document as any,
Expand Down
Loading

0 comments on commit 56f7ea6

Please sign in to comment.