From 37dbb15bbaa94df973857a79ee82363cab06e3fa Mon Sep 17 00:00:00 2001 From: Alfred Jonsson Date: Fri, 22 Mar 2024 08:44:46 +0100 Subject: [PATCH 1/2] fix: request bodies should be optional by default --- packages/core/src/getters/body.ts | 14 +- packages/core/src/getters/props.ts | 6 +- packages/core/src/types.ts | 1 + tests/configs/swr.config.ts | 11 + .../specifications/optional-request-body.yaml | 223 ++++++++++++++++++ 5 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 tests/specifications/optional-request-body.yaml diff --git a/packages/core/src/getters/body.ts b/packages/core/src/getters/body.ts index 5a199f754..b0db87254 100644 --- a/packages/core/src/getters/body.ts +++ b/packages/core/src/getters/body.ts @@ -1,7 +1,8 @@ import { ReferenceObject, RequestBodyObject } from 'openapi3-ts/oas30'; import { generalJSTypesWithArray } from '../constants'; +import { resolveRef } from '../resolvers'; import { ContextSpecs, GetterBody, OverrideOutputContentType } from '../types'; -import { camel, sanitize } from '../utils'; +import { camel, isReference, sanitize } from '../utils'; import { getResReqTypes } from './res-req-types'; export const getBody = ({ @@ -53,6 +54,7 @@ export const getBody = ({ context.output.override.components.requestBodies.suffix : camel(definition); + let isOptional = true; if (implementation) { implementation = sanitize(implementation, { underscore: '_', @@ -61,6 +63,15 @@ export const getBody = ({ es5keyword: true, es5IdentifierName: true, }); + if (isReference(requestBody)) { + const { schema: bodySchema } = resolveRef( + requestBody, + context, + ); + isOptional = !bodySchema.required; + } else { + isOptional = !requestBody.required; + } } return { @@ -69,6 +80,7 @@ export const getBody = ({ implementation, imports, schemas, + isOptional, ...(filteredBodyTypes.length === 1 ? { formData: filteredBodyTypes[0].formData, diff --git a/packages/core/src/getters/props.ts b/packages/core/src/getters/props.ts index 8ab382c94..6060952e1 100644 --- a/packages/core/src/getters/props.ts +++ b/packages/core/src/getters/props.ts @@ -25,10 +25,10 @@ export const getProps = ({ }): GetterProps => { const bodyProp = { name: body.implementation, - definition: `${body.implementation}: ${body.definition}`, - implementation: `${body.implementation}: ${body.definition}`, + definition: `${body.implementation}${body.isOptional ? '?' : ''}: ${body.definition}`, + implementation: `${body.implementation}${body.isOptional ? '?' : ''}: ${body.definition}`, default: false, - required: true, + required: !body.isOptional, type: GetterPropType.BODY, }; diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 970d16178..061cb44e2 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -728,6 +728,7 @@ export type GetterBody = { formData?: string; formUrlEncoded?: string; contentType: string; + isOptional: boolean; }; export type GetterParameters = { diff --git a/tests/configs/swr.config.ts b/tests/configs/swr.config.ts index 20de0fa69..1f667a563 100644 --- a/tests/configs/swr.config.ts +++ b/tests/configs/swr.config.ts @@ -178,4 +178,15 @@ export default defineConfig({ target: '../specifications/errors.yaml', }, }, + optionalRequestBody: { + output: { + target: '../generated/swr/optional-request-body/endpoints.ts', + schemas: '../generated/swr/optional-request-body/model', + client: 'swr', + mock: true, + }, + input: { + target: '../specifications/optional-request-body.yaml', + }, + }, }); diff --git a/tests/specifications/optional-request-body.yaml b/tests/specifications/optional-request-body.yaml new file mode 100644 index 000000000..7637fa085 --- /dev/null +++ b/tests/specifications/optional-request-body.yaml @@ -0,0 +1,223 @@ +openapi: '3.0.0' +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + post: + summary: Create a pet + operationId: createPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: string + - name: sort + in: query + description: | + Which property to sort by? + Example: name sorts ASC while -name sorts DESC. + required: true + schema: + type: string + enum: + - name + - -name + - email + - -email + - description: Header parameters + in: header + name: X-EXAMPLE + required: true + schema: + type: string + enum: + - ONE + - TWO + - THREE + requestBody: + $ref: '#/components/requestBodies/RequiredPetBody' + responses: + '200': + description: Created Pet + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + put: + summary: Update a pet + operationId: updatePets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: string + - name: sort + in: query + description: | + Which property to sort by? + Example: name sorts ASC while -name sorts DESC. + required: true + schema: + type: string + enum: + - name + - -name + - email + - -email + - description: Header parameters + in: header + name: X-EXAMPLE + required: true + schema: + type: string + enum: + - ONE + - TWO + - THREE + requestBody: + $ref: '#/components/requestBodies/OptionalPetBody' + responses: + '200': + description: Updated Pet + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + /cookies: + post: + summary: Create a cookie + operationId: createCookies + tags: + - cookies + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: string + - name: sort + in: query + description: | + Which property to sort by? + Example: name sorts ASC while -name sorts DESC. + required: true + schema: + type: string + enum: + - name + - -name + - email + - -email + - description: Header parameters + in: header + name: X-EXAMPLE + required: true + schema: + type: string + enum: + - ONE + - TWO + - THREE + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Cookie' + responses: + '200': + description: Created Cookie + content: + application/json: + schema: + $ref: '#/components/schemas/Cookie' + put: + summary: Update a cookie + operationId: updateCookies + tags: + - cookies + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: string + - name: sort + in: query + description: | + Which property to sort by? + Example: name sorts ASC while -name sorts DESC. + required: true + schema: + type: string + enum: + - name + - -name + - email + - -email + - description: Header parameters + in: header + name: X-EXAMPLE + required: true + schema: + type: string + enum: + - ONE + - TWO + - THREE + requestBody: + required: false + content: + application/json: + schema: + $ref: '#/components/schemas/Cookie' + responses: + '200': + description: Updated Cookie + content: + application/json: + schema: + $ref: '#/components/schemas/Cookie' +components: + requestBodies: + OptionalPetBody: + description: A JSON object containing pet information + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + RequiredPetBody: + description: A JSON object containing pet information + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/Pet' + schemas: + Pet: + type: object + properties: + id: + type: integer + format: int64 + Cookie: + type: object + properties: + id: + type: integer + format: int64 From 1f112d6bd3e3903ae7658e8fa9f43d5342c06d39 Mon Sep 17 00:00:00 2001 From: Alfred Jonsson Date: Fri, 29 Mar 2024 08:20:36 +0100 Subject: [PATCH 2/2] fix: request body is required by default --- packages/core/src/getters/body.ts | 8 +- .../specifications/optional-request-body.yaml | 181 +----------------- 2 files changed, 14 insertions(+), 175 deletions(-) diff --git a/packages/core/src/getters/body.ts b/packages/core/src/getters/body.ts index b0db87254..844ce53ba 100644 --- a/packages/core/src/getters/body.ts +++ b/packages/core/src/getters/body.ts @@ -54,7 +54,7 @@ export const getBody = ({ context.output.override.components.requestBodies.suffix : camel(definition); - let isOptional = true; + let isOptional = false; if (implementation) { implementation = sanitize(implementation, { underscore: '_', @@ -68,8 +68,10 @@ export const getBody = ({ requestBody, context, ); - isOptional = !bodySchema.required; - } else { + if (bodySchema.required !== undefined) { + isOptional = !bodySchema.required; + } + } else if (requestBody.required !== undefined) { isOptional = !requestBody.required; } } diff --git a/tests/specifications/optional-request-body.yaml b/tests/specifications/optional-request-body.yaml index 7637fa085..1becd3c97 100644 --- a/tests/specifications/optional-request-body.yaml +++ b/tests/specifications/optional-request-body.yaml @@ -2,184 +2,35 @@ openapi: '3.0.0' info: version: 1.0.0 title: Swagger Petstore - license: - name: MIT -servers: - - url: http://petstore.swagger.io/v1 paths: /pets: post: - summary: Create a pet operationId: createPets - tags: - - pets - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: string - - name: sort - in: query - description: | - Which property to sort by? - Example: name sorts ASC while -name sorts DESC. - required: true - schema: - type: string - enum: - - name - - -name - - email - - -email - - description: Header parameters - in: header - name: X-EXAMPLE - required: true - schema: - type: string - enum: - - ONE - - TWO - - THREE requestBody: $ref: '#/components/requestBodies/RequiredPetBody' responses: - '200': - description: Created Pet - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' + '204': + description: Ok put: - summary: Update a pet operationId: updatePets - tags: - - pets - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: string - - name: sort - in: query - description: | - Which property to sort by? - Example: name sorts ASC while -name sorts DESC. - required: true - schema: - type: string - enum: - - name - - -name - - email - - -email - - description: Header parameters - in: header - name: X-EXAMPLE - required: true - schema: - type: string - enum: - - ONE - - TWO - - THREE requestBody: $ref: '#/components/requestBodies/OptionalPetBody' responses: - '200': - description: Updated Pet - content: - application/json: - schema: - $ref: '#/components/schemas/Pet' + '204': + description: Ok /cookies: post: - summary: Create a cookie operationId: createCookies - tags: - - cookies - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: string - - name: sort - in: query - description: | - Which property to sort by? - Example: name sorts ASC while -name sorts DESC. - required: true - schema: - type: string - enum: - - name - - -name - - email - - -email - - description: Header parameters - in: header - name: X-EXAMPLE - required: true - schema: - type: string - enum: - - ONE - - TWO - - THREE requestBody: - required: true content: application/json: schema: $ref: '#/components/schemas/Cookie' responses: - '200': - description: Created Cookie - content: - application/json: - schema: - $ref: '#/components/schemas/Cookie' + '204': + description: Ok put: - summary: Update a cookie operationId: updateCookies - tags: - - cookies - parameters: - - name: limit - in: query - description: How many items to return at one time (max 100) - required: false - schema: - type: string - - name: sort - in: query - description: | - Which property to sort by? - Example: name sorts ASC while -name sorts DESC. - required: true - schema: - type: string - enum: - - name - - -name - - email - - -email - - description: Header parameters - in: header - name: X-EXAMPLE - required: true - schema: - type: string - enum: - - ONE - - TWO - - THREE requestBody: required: false content: @@ -187,23 +38,17 @@ paths: schema: $ref: '#/components/schemas/Cookie' responses: - '200': - description: Updated Cookie - content: - application/json: - schema: - $ref: '#/components/schemas/Cookie' + '204': + description: Ok components: requestBodies: OptionalPetBody: - description: A JSON object containing pet information + required: false content: application/json: schema: $ref: '#/components/schemas/Pet' RequiredPetBody: - description: A JSON object containing pet information - required: true content: application/json: schema: @@ -211,13 +56,5 @@ components: schemas: Pet: type: object - properties: - id: - type: integer - format: int64 Cookie: type: object - properties: - id: - type: integer - format: int64