From 1df132d2981341b039fe1a4b9237c3d4eed8ff14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=9A=80=20Jack?= Date: Thu, 24 Oct 2024 16:13:45 +1100 Subject: [PATCH] fix(type-safe-api): generate models for inline request body schemas Inline request body schemas were typed as `any` and no model was generated for them. Address this by hoisting inline request schemas in the same way we do for responses. Note that OpenAPI generator named these hoisted inline request models `Request` which also clashes with the overall operation request model - and resolved it by appending `Operation` to the Operation ID (see #789). We deviate from OpenAPI generator behaviour to avoid this issue recurring by naming the type `RequestContent`. --- .../type-safe-api/generators/generate-next.ts | 37 +- .../test/resources/specs/edge-cases.yaml | 17 + .../__snapshots__/java.test.ts.snap | 1041 +++++++++++++++-- .../__snapshots__/python.test.ts.snap | 552 +++++++++ .../__snapshots__/typescript.test.ts.snap | 232 +++- 5 files changed, 1757 insertions(+), 122 deletions(-) diff --git a/packages/type-safe-api/scripts/type-safe-api/generators/generate-next.ts b/packages/type-safe-api/scripts/type-safe-api/generators/generate-next.ts index 924f0bfd7..423529e86 100755 --- a/packages/type-safe-api/scripts/type-safe-api/generators/generate-next.ts +++ b/packages/type-safe-api/scripts/type-safe-api/generators/generate-next.ts @@ -718,21 +718,34 @@ const buildData = async (inSpec: OpenAPIV3.Document, metadata: any) => { }; } - // "Hoist" inline response schemas + // "Hoist" inline request and response schemas Object.entries(spec.paths ?? {}).forEach(([path, pathOps]) => Object.entries(pathOps ?? {}).forEach(([method, op]) => { const operation = resolveIfRef(spec, op); - if (operation && typeof operation === "object" && "responses" in operation) { - Object.entries(operation.responses ?? {}).forEach(([code, res]) => { - const response = resolveIfRef(spec, res); - const jsonResponseSchema = response?.content?.['application/json']?.schema; - if (jsonResponseSchema && !isRef(jsonResponseSchema) && ["object", "array"].includes(jsonResponseSchema.type!)) { - const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}${code}Response`; - spec.components!.schemas![schemaName] = jsonResponseSchema; - response!.content!['application/json'].schema = { - $ref: `#/components/schemas/${schemaName}`, - }; + if (operation && typeof operation === "object") { + if ("responses" in operation) { + Object.entries(operation.responses ?? {}).forEach(([code, res]) => { + const response = resolveIfRef(spec, res); + const jsonResponseSchema = response?.content?.['application/json']?.schema; + if (jsonResponseSchema && !isRef(jsonResponseSchema) && ["object", "array"].includes(jsonResponseSchema.type!)) { + const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}${code}Response`; + spec.components!.schemas![schemaName] = jsonResponseSchema; + response!.content!['application/json'].schema = { + $ref: `#/components/schemas/${schemaName}`, + }; + } + }); + } + if ("requestBody" in operation) { + const requestBody = resolveIfRef(spec, operation.requestBody); + const jsonRequestSchema = requestBody?.content?.['application/json']?.schema; + if (jsonRequestSchema && !isRef(jsonRequestSchema) && ["object", "array"].includes(jsonRequestSchema.type!)) { + const schemaName = `${_upperFirst(_camelCase(operation.operationId ?? `${path}-${method}`))}RequestContent`; + spec.components!.schemas![schemaName] = jsonRequestSchema; + requestBody!.content!['application/json'].schema = { + $ref: `#/components/schemas/${schemaName}`, + }; } - }); + } } })); diff --git a/packages/type-safe-api/test/resources/specs/edge-cases.yaml b/packages/type-safe-api/test/resources/specs/edge-cases.yaml index 49ce1f1db..0e430b00b 100644 --- a/packages/type-safe-api/test/resources/specs/edge-cases.yaml +++ b/packages/type-safe-api/test/resources/specs/edge-cases.yaml @@ -101,6 +101,23 @@ paths: enum: - fruit - vegetable + /inline-request-body: + post: + operationId: inlineRequestBody + responses: + 204: + description: ok + requestBody: + content: + application/json: + schema: + type: object + properties: + someProperty: + type: + string + required: + - someProperty components: schemas: MyEnum: diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap index 1887efba3..31879aaa5 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/java.test.ts.snap @@ -30335,21 +30335,27 @@ src/main/java/test/test/runtime/api/handlers/InterceptorWarmupChainedRequestInpu src/main/java/test/test/runtime/api/handlers/InterceptorWithWarmup.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParametersResponse.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnumResponse.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyResponse.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsResponse.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParameters200Response.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnum200Response.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBody204Response.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywords200Response.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParametersRequestParameters.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnumRequestParameters.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyRequestParameters.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsRequestParameters.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParametersInput.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnumInput.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyInput.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsInput.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParametersRequestInput.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnumRequestInput.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyRequestInput.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsRequestInput.java src/main/java/test/test/runtime/api/handlers/array_request_parameters/ArrayRequestParameters.java src/main/java/test/test/runtime/api/handlers/inline_enum/InlineEnum.java +src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBody.java src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywords.java src/main/java/test/test/runtime/api/handlers/HandlerRouter.java src/main/java/test/test/runtime/api/interceptors/TryCatchInterceptor.java @@ -30382,6 +30388,7 @@ src/main/java/test/test/runtime/StringUtil.java src/main/java/test/test/runtime/model/AbstractOpenApiSchema.java src/main/java/test/test/runtime/model/InlineEnum200Response.java src/main/java/test/test/runtime/model/InlineEnum200ResponseCategoryEnum.java +src/main/java/test/test/runtime/model/InlineRequestBodyRequestContent.java src/main/java/test/test/runtime/model/MyEnum.java", "src/main/java/test/test/runtime/ApiCallback.java": "/* * Edge Cases @@ -32450,6 +32457,7 @@ public class JSON { gsonBuilder.registerTypeAdapter(LocalDate.class, localDateTypeAdapter); gsonBuilder.registerTypeAdapter(byte[].class, byteArrayAdapter); gsonBuilder.registerTypeAdapterFactory(new test.test.runtime.model.InlineEnum200Response.CustomTypeAdapterFactory()); + gsonBuilder.registerTypeAdapterFactory(new test.test.runtime.model.InlineRequestBodyRequestContent.CustomTypeAdapterFactory()); gson = gsonBuilder.create(); } @@ -33151,6 +33159,7 @@ import java.io.IOException; import java.math.BigDecimal; import java.io.File; import test.test.runtime.model.InlineEnum200Response; +import test.test.runtime.model.InlineRequestBodyRequestContent; import test.test.runtime.model.MyEnum; import java.lang.reflect.Type; @@ -33617,6 +33626,158 @@ public class DefaultApi { public APIinlineEnumRequest inlineEnum() { return new APIinlineEnumRequest(); } + private okhttp3.Call inlineRequestBodyCall(InlineRequestBodyRequestContent inlineRequestBodyRequestContent, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = inlineRequestBodyRequestContent; + + // create path and map variables + String localVarPath = "/inline-request-body"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + "application/json" + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { }; + return localVarApiClient.buildCall(basePath, localVarPath, "POST", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + + @SuppressWarnings("rawtypes") + private okhttp3.Call inlineRequestBodyValidateBeforeCall(InlineRequestBodyRequestContent inlineRequestBodyRequestContent, final ApiCallback _callback) throws ApiException { + return inlineRequestBodyCall(inlineRequestBodyRequestContent, _callback); + + } + + private ApiResponse inlineRequestBodyWithHttpInfo(InlineRequestBodyRequestContent inlineRequestBodyRequestContent) throws ApiException { + okhttp3.Call localVarCall = inlineRequestBodyValidateBeforeCall(inlineRequestBodyRequestContent, null); + return localVarApiClient.execute(localVarCall); + } + + + private okhttp3.Call inlineRequestBodyAsync(InlineRequestBodyRequestContent inlineRequestBodyRequestContent, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = inlineRequestBodyValidateBeforeCall(inlineRequestBodyRequestContent, _callback); + localVarApiClient.executeAsync(localVarCall, _callback); + return localVarCall; + } + + public class APIinlineRequestBodyRequest { + private InlineRequestBodyRequestContent inlineRequestBodyRequestContent; + + private APIinlineRequestBodyRequest() { + } + + /** + * Set inlineRequestBodyRequestContent + * @param inlineRequestBodyRequestContent (optional) + * @return APIinlineRequestBodyRequest + */ + public APIinlineRequestBodyRequest inlineRequestBodyRequestContent(InlineRequestBodyRequestContent inlineRequestBodyRequestContent) { + this.inlineRequestBodyRequestContent = inlineRequestBodyRequestContent; + return this; + } + + /** + * Build call for inlineRequestBody + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + +
Status Code Description Response Headers
204 ok -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return inlineRequestBodyCall(inlineRequestBodyRequestContent, _callback); + } + + /** + * Execute inlineRequestBody request + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + +
Status Code Description Response Headers
204 ok -
+ */ + public void execute() throws ApiException { + inlineRequestBodyWithHttpInfo(inlineRequestBodyRequestContent); + } + + /** + * Execute inlineRequestBody request with HTTP info returned + * @return ApiResponse<Void> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + +
Status Code Description Response Headers
204 ok -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return inlineRequestBodyWithHttpInfo(inlineRequestBodyRequestContent); + } + + /** + * Execute inlineRequestBody request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + +
Status Code Description Response Headers
204 ok -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return inlineRequestBodyAsync(inlineRequestBodyRequestContent, _callback); + } + } + + /** + * + * + * @return APIinlineRequestBodyRequest + * @http.response.details + + + +
Status Code Description Response Headers
204 ok -
+ */ + + public APIinlineRequestBodyRequest inlineRequestBody() { + return new APIinlineRequestBodyRequest(); + } private okhttp3.Call reservedKeywordsCall(String with, String _if, String propertyClass, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers @@ -33852,6 +34013,7 @@ package test.test.runtime.api.handlers; import test.test.runtime.api.handlers.array_request_parameters.*; import test.test.runtime.api.handlers.inline_enum.*; +import test.test.runtime.api.handlers.inline_request_body.*; import test.test.runtime.api.handlers.reserved_keywords.*; import test.test.runtime.api.handlers.Handlers; @@ -33872,10 +34034,12 @@ import java.util.Collections; public abstract class HandlerRouter implements RequestHandler { private static final String arrayRequestParametersMethodAndPath = Handlers.concatMethodAndPath("GET", "/array-request-parameters"); private static final String inlineEnumMethodAndPath = Handlers.concatMethodAndPath("GET", "/inline-enum"); + private static final String inlineRequestBodyMethodAndPath = Handlers.concatMethodAndPath("POST", "/inline-request-body"); private static final String reservedKeywordsMethodAndPath = Handlers.concatMethodAndPath("GET", "/reserved-keywords"); private final ArrayRequestParameters constructedArrayRequestParameters; private final InlineEnum constructedInlineEnum; + private final InlineRequestBody constructedInlineRequestBody; private final ReservedKeywords constructedReservedKeywords; /** @@ -33886,6 +34050,10 @@ public abstract class HandlerRouter implements RequestHandler> inlineEnumInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); inlineEnumInterceptors.addAll(this.getInterceptors()); return this.constructedInlineEnum.handleRequestWithAdditionalInterceptors(event, context, inlineEnumInterceptors); + case inlineRequestBodyRoute: + List> inlineRequestBodyInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); + inlineRequestBodyInterceptors.addAll(this.getInterceptors()); + return this.constructedInlineRequestBody.handleRequestWithAdditionalInterceptors(event, context, inlineRequestBodyInterceptors); case reservedKeywordsRoute: List> reservedKeywordsInterceptors = Handlers.getAnnotationInterceptors(this.getClass()); reservedKeywordsInterceptors.addAll(this.getInterceptors()); @@ -35461,8 +35636,8 @@ import test.test.runtime.api.handlers.Response; */ public interface InlineEnumResponse extends Response {} ", - "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywords.java": " -package test.test.runtime.api.handlers.reserved_keywords; + "src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBody.java": " +package test.test.runtime.api.handlers.inline_request_body; import test.test.runtime.model.*; import test.test.runtime.JSON; @@ -35486,50 +35661,50 @@ import org.crac.Resource; /** - * Lambda handler wrapper for the reservedKeywords operation + * Lambda handler wrapper for the inlineRequestBody operation */ -public abstract class ReservedKeywords implements RequestHandler, Resource { +public abstract class InlineRequestBody implements RequestHandler, Resource { { Core.getGlobalContext().register(this); } /** - * Handle the request for the reservedKeywords operation + * Handle the request for the inlineRequestBody operation */ - public abstract ReservedKeywordsResponse handle(final ReservedKeywordsRequestInput request); + public abstract InlineRequestBodyResponse handle(final InlineRequestBodyRequestInput request); /** * Interceptors that the handler class has been decorated with */ - private List> annotationInterceptors = Handlers.getAnnotationInterceptors(ReservedKeywords.class); + private List> annotationInterceptors = Handlers.getAnnotationInterceptors(InlineRequestBody.class); /** * For more complex interceptors that require instantiation with parameters, you may override this method to * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, * prefer the @Interceptors annotation. */ - public List> getInterceptors() { + public List> getInterceptors() { return Collections.emptyList(); } - private List> getHandlerInterceptors() { - List> interceptors = new ArrayList<>(); + private List> getHandlerInterceptors() { + List> interceptors = new ArrayList<>(); interceptors.addAll(annotationInterceptors); interceptors.addAll(this.getInterceptors()); return interceptors; } - private HandlerChain buildChain(List> interceptors) { - return Handlers.buildHandlerChain(interceptors, new HandlerChain() { + private HandlerChain buildChain(List> interceptors) { + return Handlers.buildHandlerChain(interceptors, new HandlerChain() { @Override - public Response next(ChainedRequestInput input) { - return handle(new ReservedKeywordsRequestInput(input.getEvent(), input.getContext(), input.getInterceptorContext(), input.getInput())); + public Response next(ChainedRequestInput input) { + return handle(new InlineRequestBodyRequestInput(input.getEvent(), input.getContext(), input.getInterceptorContext(), input.getInput())); } }); } - private ChainedRequestInput buildChainedRequestInput(final APIGatewayProxyRequestEvent event, final Context context, final ReservedKeywordsInput input, final Map interceptorContext) { - return new ChainedRequestInput() { + private ChainedRequestInput buildChainedRequestInput(final APIGatewayProxyRequestEvent event, final Context context, final InlineRequestBodyInput input, final Map interceptorContext) { + return new ChainedRequestInput() { @Override public HandlerChain getChain() { // The chain's next method ignores the chain given as input, and is pre-built to follow the remaining @@ -35548,7 +35723,7 @@ public abstract class ReservedKeywords implements RequestHandler()) .withQueryStringParameters(new HashMap<>()) @@ -35609,20 +35784,20 @@ public abstract class ReservedKeywords implements RequestHandler> additionalInterceptors) { + public APIGatewayProxyResponseEvent handleRequestWithAdditionalInterceptors(final APIGatewayProxyRequestEvent event, final Context context, final List> additionalInterceptors) { final Map interceptorContext = new HashMap<>(); - interceptorContext.put("operationId", "reservedKeywords"); + interceptorContext.put("operationId", "inlineRequestBody"); - List> interceptors = new ArrayList<>(); + List> interceptors = new ArrayList<>(); interceptors.addAll(additionalInterceptors); interceptors.addAll(this.getHandlerInterceptors()); final HandlerChain chain = this.buildChain(interceptors); - ReservedKeywordsInput input; + InlineRequestBodyInput input; try { - input = new ReservedKeywordsInput(event); + input = new InlineRequestBodyInput(event); } catch (RuntimeException e) { Map headers = new HashMap<>(); headers.putAll(Handlers.extractResponseHeadersFromInterceptors(interceptors)); @@ -35647,8 +35822,8 @@ public abstract class ReservedKeywords implements RequestHandler headers; private final Map> multiValueHeaders; - private ReservedKeywords200Response(final Map headers, final Map> multiValueHeaders) { + private InlineRequestBody204Response(final Map headers, final Map> multiValueHeaders) { this.body = ""; this.headers = headers; @@ -35682,7 +35857,7 @@ public class ReservedKeywords200Response extends RuntimeException implements Res @Override public int getStatusCode() { - return 200; + return 204; } @Override @@ -35702,29 +35877,29 @@ public class ReservedKeywords200Response extends RuntimeException implements Res } /** - * Create a ReservedKeywords200Response without a body + * Create a InlineRequestBody204Response without a body */ - public static ReservedKeywords200Response of() { - return new ReservedKeywords200Response(new HashMap<>(), new HashMap<>()); + public static InlineRequestBody204Response of() { + return new InlineRequestBody204Response(new HashMap<>(), new HashMap<>()); } /** - * Create a ReservedKeywords200Response without a body and headers + * Create a InlineRequestBody204Response without a body and headers */ - public static ReservedKeywords200Response of(final Map headers) { - return new ReservedKeywords200Response(headers, new HashMap<>()); + public static InlineRequestBody204Response of(final Map headers) { + return new InlineRequestBody204Response(headers, new HashMap<>()); } /** - * Create a ReservedKeywords200Response without a body, headers and multi-value headers + * Create a InlineRequestBody204Response without a body, headers and multi-value headers */ - public static ReservedKeywords200Response of(final Map headers, final Map> multiValueHeaders) { - return new ReservedKeywords200Response(headers, multiValueHeaders); + public static InlineRequestBody204Response of(final Map headers, final Map> multiValueHeaders) { + return new InlineRequestBody204Response(headers, multiValueHeaders); } } ", - "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsInput.java": " -package test.test.runtime.api.handlers.reserved_keywords; + "src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyInput.java": " +package test.test.runtime.api.handlers.inline_request_body; import test.test.runtime.model.*; import test.test.runtime.JSON; @@ -35737,11 +35912,11 @@ import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import java.io.IOException; /** - * Input for the reservedKeywords operation + * Input for the inlineRequestBody operation */ @lombok.Builder @lombok.AllArgsConstructor -public class ReservedKeywordsInput { +public class InlineRequestBodyInput { static { // JSON has a static instance of Gson which is instantiated lazily the first time it is initialised. // Create an instance here if required to ensure that the static Gson instance is always available. @@ -35750,20 +35925,29 @@ public class ReservedKeywordsInput { } } - private final ReservedKeywordsRequestParameters requestParameters; + private final InlineRequestBodyRequestParameters requestParameters; + private final InlineRequestBodyRequestContent body; - public ReservedKeywordsInput(final APIGatewayProxyRequestEvent event) { - this.requestParameters = new ReservedKeywordsRequestParameters(event); + public InlineRequestBodyInput(final APIGatewayProxyRequestEvent event) { + this.requestParameters = new InlineRequestBodyRequestParameters(event); + try { + this.body = InlineRequestBodyRequestContent.fromJson(event.getBody()); + } catch (IOException e) { + throw new RuntimeException(e); + }; } - public ReservedKeywordsRequestParameters getRequestParameters() { + public InlineRequestBodyRequestParameters getRequestParameters() { return this.requestParameters; } + public InlineRequestBodyRequestContent getBody() { + return this.body; + } } ", - "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsRequestInput.java": " -package test.test.runtime.api.handlers.reserved_keywords; + "src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyRequestInput.java": " +package test.test.runtime.api.handlers.inline_request_body; import test.test.runtime.model.*; import test.test.runtime.api.handlers.RequestInput; @@ -35776,20 +35960,20 @@ import java.io.IOException; import com.amazonaws.services.lambda.runtime.Context; /** - * Full request input for the reservedKeywords operation, including the raw API Gateway event + * Full request input for the inlineRequestBody operation, including the raw API Gateway event */ @lombok.Builder @lombok.AllArgsConstructor -public class ReservedKeywordsRequestInput implements RequestInput { +public class InlineRequestBodyRequestInput implements RequestInput { private final APIGatewayProxyRequestEvent event; private final Context context; private final Map interceptorContext; - private final ReservedKeywordsInput input; + private final InlineRequestBodyInput input; /** * Returns the typed request input, with path, query and body parameters */ - public ReservedKeywordsInput getInput() { + public InlineRequestBodyInput getInput() { return this.input; } @@ -35815,8 +35999,8 @@ public class ReservedKeywordsRequestInput implements RequestInput with; - private final Optional _if; - private final Optional propertyClass; +public class InlineRequestBodyRequestParameters { - public ReservedKeywordsRequestParameters(final APIGatewayProxyRequestEvent event) { + public InlineRequestBodyRequestParameters(final APIGatewayProxyRequestEvent event) { Map rawStringParameters = new HashMap<>(); Handlers.putAllFromNullableMap(event.getPathParameters(), rawStringParameters); Handlers.putAllFromNullableMap(event.getQueryStringParameters(), rawStringParameters); @@ -35854,72 +36035,479 @@ public class ReservedKeywordsRequestParameters { Handlers.putAllFromNullableMap(event.getMultiValueHeaders(), rawStringArrayParameters); Map> decodedStringArrayParameters = Handlers.decodeRequestArrayParameters(rawStringArrayParameters); - this.with = Optional.ofNullable(Handlers.coerceStringParameter("with", false, decodedStringParameters)); - this._if = Optional.ofNullable(Handlers.coerceStringParameter("if", false, decodedStringParameters)); - this.propertyClass = Optional.ofNullable(Handlers.coerceStringParameter("class", false, decodedStringParameters)); } - public Optional getWith() { - return this.with; - } - public Optional getIf() { - return this._if; - } - public Optional getPropertyClass() { - return this.propertyClass; - } } ", - "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsResponse.java": " -package test.test.runtime.api.handlers.reserved_keywords; + "src/main/java/test/test/runtime/api/handlers/inline_request_body/InlineRequestBodyResponse.java": " +package test.test.runtime.api.handlers.inline_request_body; import test.test.runtime.api.handlers.Response; /** - * Response for the reservedKeywords operation + * Response for the inlineRequestBody operation */ -public interface ReservedKeywordsResponse extends Response {} +public interface InlineRequestBodyResponse extends Response {} ", - "src/main/java/test/test/runtime/api/interceptors/DefaultInterceptors.java": "package test.test.runtime.api.interceptors; + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywords.java": " +package test.test.runtime.api.handlers.reserved_keywords; -import test.test.runtime.api.interceptors.powertools.LoggingInterceptor; -import test.test.runtime.api.interceptors.powertools.MetricsInterceptor; -import test.test.runtime.api.interceptors.powertools.TracingInterceptor; +import test.test.runtime.model.*; +import test.test.runtime.JSON; import test.test.runtime.api.handlers.Interceptor; +import test.test.runtime.api.handlers.Handlers; +import test.test.runtime.api.handlers.*; -import java.util.Arrays; import java.util.List; - -public class DefaultInterceptors { - public static List> all() { - return Arrays.asList( - new ResponseHeadersInterceptor<>(), - new LoggingInterceptor<>(), - new TryCatchInterceptor<>(), - new TracingInterceptor<>(), - new MetricsInterceptor<>() - ); - } -}", - "src/main/java/test/test/runtime/api/interceptors/ResponseHeadersInterceptor.java": "package test.test.runtime.api.interceptors; - -import test.test.runtime.api.handlers.ChainedRequestInput; -import test.test.runtime.api.handlers.Response; -import test.test.runtime.api.handlers.Interceptor; -import test.test.runtime.api.handlers.InterceptorWithWarmup; +import java.util.ArrayList; +import java.util.Optional; import java.util.Map; import java.util.HashMap; +import java.util.Collections; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; +import java.io.IOException; +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import org.crac.Core; +import org.crac.Resource; + /** - * An interceptor for adding cross-origin resource sharing (CORS) headers to the response. - * Allows all origins and headers. + * Lambda handler wrapper for the reservedKeywords operation */ -public class ResponseHeadersInterceptor extends InterceptorWithWarmup { - private final Map additionalHeaders; +public abstract class ReservedKeywords implements RequestHandler, Resource { + { + Core.getGlobalContext().register(this); + } - public ResponseHeadersInterceptor() { - this.additionalHeaders = new HashMap<>(); - this.additionalHeaders.put("Access-Control-Allow-Origin", "*"); + /** + * Handle the request for the reservedKeywords operation + */ + public abstract ReservedKeywordsResponse handle(final ReservedKeywordsRequestInput request); + + /** + * Interceptors that the handler class has been decorated with + */ + private List> annotationInterceptors = Handlers.getAnnotationInterceptors(ReservedKeywords.class); + + /** + * For more complex interceptors that require instantiation with parameters, you may override this method to + * return a list of instantiated interceptors. For simple interceptors with no need for constructor arguments, + * prefer the @Interceptors annotation. + */ + public List> getInterceptors() { + return Collections.emptyList(); + } + + private List> getHandlerInterceptors() { + List> interceptors = new ArrayList<>(); + interceptors.addAll(annotationInterceptors); + interceptors.addAll(this.getInterceptors()); + return interceptors; + } + + private HandlerChain buildChain(List> interceptors) { + return Handlers.buildHandlerChain(interceptors, new HandlerChain() { + @Override + public Response next(ChainedRequestInput input) { + return handle(new ReservedKeywordsRequestInput(input.getEvent(), input.getContext(), input.getInterceptorContext(), input.getInput())); + } + }); + } + + private ChainedRequestInput buildChainedRequestInput(final APIGatewayProxyRequestEvent event, final Context context, final ReservedKeywordsInput input, final Map interceptorContext) { + return new ChainedRequestInput() { + @Override + public HandlerChain getChain() { + // The chain's next method ignores the chain given as input, and is pre-built to follow the remaining + // chain. + return null; + } + + @Override + public APIGatewayProxyRequestEvent getEvent() { + return event; + } + + @Override + public Context getContext() { + return context; + } + + @Override + public ReservedKeywordsInput getInput() { + return input; + } + + @Override + public Map getInterceptorContext() { + return interceptorContext; + } + }; + } + + @Override + public void beforeCheckpoint(org.crac.Context context) { + // Prime building the handler chain which can take a few 100ms to JIT. + this.buildChain(this.getHandlerInterceptors()); + this.buildChainedRequestInput(null, null, null, null); + + // Initialise instance of Gson and prime serialisation and deserialisation + new JSON(); + JSON.getGson().fromJson(JSON.getGson().toJson(new ApiResponse("", 0, new HashMap<>(), new HashMap<>())), ApiResponse.class); + + try { + // Prime input validation - this will likely fail for the fake event but ensures the code path is optimised + // ready for a real invocation + new ReservedKeywordsInput(new APIGatewayProxyRequestEvent() + .withBody("{}") + .withPathParameters(new HashMap<>()) + .withQueryStringParameters(new HashMap<>()) + .withMultiValueQueryStringParameters(new HashMap<>()) + .withHeaders(new HashMap<>()) + .withMultiValueHeaders(new HashMap<>()) + ); + } catch (Exception e) { + + } + + this.warmUp(); + } + + @Override + public void afterRestore(org.crac.Context context) { + + } + + /** + * Override this method to perform any warmup activities which will be executed prior to the snap-start snapshot. + */ + public void warmUp() { + + } + + @Override + public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent event, final Context context) { + return this.handleRequestWithAdditionalInterceptors(event, context, new ArrayList<>()); + } + + private Map getErrorResponseHeaders(final int statusCode) { + Map headers = new HashMap<>(); + return headers; + } + + public APIGatewayProxyResponseEvent handleRequestWithAdditionalInterceptors(final APIGatewayProxyRequestEvent event, final Context context, final List> additionalInterceptors) { + final Map interceptorContext = new HashMap<>(); + interceptorContext.put("operationId", "reservedKeywords"); + + List> interceptors = new ArrayList<>(); + interceptors.addAll(additionalInterceptors); + interceptors.addAll(this.getHandlerInterceptors()); + + final HandlerChain chain = this.buildChain(interceptors); + + ReservedKeywordsInput input; + + try { + input = new ReservedKeywordsInput(event); + } catch (RuntimeException e) { + Map headers = new HashMap<>(); + headers.putAll(Handlers.extractResponseHeadersFromInterceptors(interceptors)); + headers.putAll(this.getErrorResponseHeaders(400)); + return new APIGatewayProxyResponseEvent() + .withStatusCode(400) + .withHeaders(headers) + .withBody("{\\"message\\": \\"" + e.getMessage() + "\\"}"); + } + + final Response response = chain.next(this.buildChainedRequestInput(event, context, input, interceptorContext)); + + Map responseHeaders = new HashMap<>(); + responseHeaders.putAll(this.getErrorResponseHeaders(response.getStatusCode())); + responseHeaders.putAll(response.getHeaders()); + + return new APIGatewayProxyResponseEvent() + .withStatusCode(response.getStatusCode()) + .withHeaders(responseHeaders) + .withMultiValueHeaders(response.getMultiValueHeaders()) + .withBody(response.getBody()); + } +} +", + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywords200Response.java": " +package test.test.runtime.api.handlers.reserved_keywords; + +import test.test.runtime.model.*; +import test.test.runtime.JSON; +import java.util.Map; +import java.util.HashMap; +import java.util.List; + +/** + * Response with status code 200 for the reservedKeywords operation + */ +public class ReservedKeywords200Response extends RuntimeException implements ReservedKeywordsResponse { + static { + // JSON has a static instance of Gson which is instantiated lazily the first time it is initialised. + // Create an instance here if required to ensure that the static Gson instance is always available. + if (JSON.getGson() == null) { + new JSON(); + } + } + + private final String body; + + private final Map headers; + private final Map> multiValueHeaders; + + private ReservedKeywords200Response(final Map headers, final Map> multiValueHeaders) { + + this.body = ""; + this.headers = headers; + this.multiValueHeaders = multiValueHeaders; + } + + @Override + public int getStatusCode() { + return 200; + } + + @Override + public String getBody() { + return this.body; + } + + + @Override + public Map getHeaders() { + return this.headers; + } + + @Override + public Map> getMultiValueHeaders() { + return this.multiValueHeaders; + } + + /** + * Create a ReservedKeywords200Response without a body + */ + public static ReservedKeywords200Response of() { + return new ReservedKeywords200Response(new HashMap<>(), new HashMap<>()); + } + + /** + * Create a ReservedKeywords200Response without a body and headers + */ + public static ReservedKeywords200Response of(final Map headers) { + return new ReservedKeywords200Response(headers, new HashMap<>()); + } + + /** + * Create a ReservedKeywords200Response without a body, headers and multi-value headers + */ + public static ReservedKeywords200Response of(final Map headers, final Map> multiValueHeaders) { + return new ReservedKeywords200Response(headers, multiValueHeaders); + } +} +", + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsInput.java": " +package test.test.runtime.api.handlers.reserved_keywords; + +import test.test.runtime.model.*; +import test.test.runtime.JSON; +import java.util.List; +import java.util.ArrayList; +import java.util.Optional; +import java.util.Map; +import java.util.HashMap; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import java.io.IOException; + +/** + * Input for the reservedKeywords operation + */ +@lombok.Builder +@lombok.AllArgsConstructor +public class ReservedKeywordsInput { + static { + // JSON has a static instance of Gson which is instantiated lazily the first time it is initialised. + // Create an instance here if required to ensure that the static Gson instance is always available. + if (JSON.getGson() == null) { + new JSON(); + } + } + + private final ReservedKeywordsRequestParameters requestParameters; + + public ReservedKeywordsInput(final APIGatewayProxyRequestEvent event) { + this.requestParameters = new ReservedKeywordsRequestParameters(event); + } + + public ReservedKeywordsRequestParameters getRequestParameters() { + return this.requestParameters; + } + +} +", + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsRequestInput.java": " +package test.test.runtime.api.handlers.reserved_keywords; + +import test.test.runtime.model.*; +import test.test.runtime.api.handlers.RequestInput; +import java.util.List; +import java.util.Optional; +import java.util.Map; +import java.util.HashMap; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; +import java.io.IOException; +import com.amazonaws.services.lambda.runtime.Context; + +/** + * Full request input for the reservedKeywords operation, including the raw API Gateway event + */ +@lombok.Builder +@lombok.AllArgsConstructor +public class ReservedKeywordsRequestInput implements RequestInput { + private final APIGatewayProxyRequestEvent event; + private final Context context; + private final Map interceptorContext; + private final ReservedKeywordsInput input; + + /** + * Returns the typed request input, with path, query and body parameters + */ + public ReservedKeywordsInput getInput() { + return this.input; + } + + /** + * Returns the raw API Gateway event + */ + public APIGatewayProxyRequestEvent getEvent() { + return this.event; + } + + /** + * Returns the lambda context + */ + public Context getContext() { + return this.context; + } + + /** + * Returns the interceptor context, which may contain values set by request interceptors + */ + public Map getInterceptorContext() { + return this.interceptorContext; + } +} +", + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsRequestParameters.java": " +package test.test.runtime.api.handlers.reserved_keywords; + +import test.test.runtime.api.handlers.Handlers; +import java.util.Optional; +import java.util.Map; +import java.util.List; +import java.util.ArrayList; +import java.util.HashMap; +import java.time.OffsetDateTime; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.stream.Collectors; +import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; + +import test.test.runtime.model.*; + +/** + * Query, path and header parameters for the ReservedKeywords operation + */ +@lombok.Builder +@lombok.AllArgsConstructor +public class ReservedKeywordsRequestParameters { + private final Optional with; + private final Optional _if; + private final Optional propertyClass; + + public ReservedKeywordsRequestParameters(final APIGatewayProxyRequestEvent event) { + Map rawStringParameters = new HashMap<>(); + Handlers.putAllFromNullableMap(event.getPathParameters(), rawStringParameters); + Handlers.putAllFromNullableMap(event.getQueryStringParameters(), rawStringParameters); + Handlers.putAllFromNullableMap(event.getHeaders(), rawStringParameters); + Map decodedStringParameters = Handlers.decodeRequestParameters(rawStringParameters); + + Map> rawStringArrayParameters = new HashMap<>(); + Handlers.putAllFromNullableMap(event.getMultiValueQueryStringParameters(), rawStringArrayParameters); + Handlers.putAllFromNullableMap(event.getMultiValueHeaders(), rawStringArrayParameters); + Map> decodedStringArrayParameters = Handlers.decodeRequestArrayParameters(rawStringArrayParameters); + + this.with = Optional.ofNullable(Handlers.coerceStringParameter("with", false, decodedStringParameters)); + this._if = Optional.ofNullable(Handlers.coerceStringParameter("if", false, decodedStringParameters)); + this.propertyClass = Optional.ofNullable(Handlers.coerceStringParameter("class", false, decodedStringParameters)); + } + + public Optional getWith() { + return this.with; + } + public Optional getIf() { + return this._if; + } + public Optional getPropertyClass() { + return this.propertyClass; + } +} +", + "src/main/java/test/test/runtime/api/handlers/reserved_keywords/ReservedKeywordsResponse.java": " +package test.test.runtime.api.handlers.reserved_keywords; + +import test.test.runtime.api.handlers.Response; + +/** + * Response for the reservedKeywords operation + */ +public interface ReservedKeywordsResponse extends Response {} +", + "src/main/java/test/test/runtime/api/interceptors/DefaultInterceptors.java": "package test.test.runtime.api.interceptors; + +import test.test.runtime.api.interceptors.powertools.LoggingInterceptor; +import test.test.runtime.api.interceptors.powertools.MetricsInterceptor; +import test.test.runtime.api.interceptors.powertools.TracingInterceptor; +import test.test.runtime.api.handlers.Interceptor; + +import java.util.Arrays; +import java.util.List; + +public class DefaultInterceptors { + public static List> all() { + return Arrays.asList( + new ResponseHeadersInterceptor<>(), + new LoggingInterceptor<>(), + new TryCatchInterceptor<>(), + new TracingInterceptor<>(), + new MetricsInterceptor<>() + ); + } +}", + "src/main/java/test/test/runtime/api/interceptors/ResponseHeadersInterceptor.java": "package test.test.runtime.api.interceptors; + +import test.test.runtime.api.handlers.ChainedRequestInput; +import test.test.runtime.api.handlers.Response; +import test.test.runtime.api.handlers.Interceptor; +import test.test.runtime.api.handlers.InterceptorWithWarmup; +import java.util.Map; +import java.util.HashMap; + +/** + * An interceptor for adding cross-origin resource sharing (CORS) headers to the response. + * Allows all origins and headers. + */ +public class ResponseHeadersInterceptor extends InterceptorWithWarmup { + private final Map additionalHeaders; + + public ResponseHeadersInterceptor() { + this.additionalHeaders = new HashMap<>(); + this.additionalHeaders.put("Access-Control-Allow-Origin", "*"); this.additionalHeaders.put("Access-Control-Allow-Headers", "*"); } @@ -36233,12 +36821,14 @@ import java.util.Map; public class OperationConfig { private T arrayRequestParameters; private T inlineEnum; + private T inlineRequestBody; private T reservedKeywords; public Map asMap() { Map map = new HashMap<>(); map.put("arrayRequestParameters", this.arrayRequestParameters); map.put("inlineEnum", this.inlineEnum); + map.put("inlineRequestBody", this.inlineRequestBody); map.put("reservedKeywords", this.reservedKeywords); return map; } @@ -36279,6 +36869,11 @@ public class OperationLookup { .method("GET") .contentTypes(Arrays.asList("application/json")) .build()); + config.put("inlineRequestBody", OperationLookupEntry.builder() + .path("/inline-request-body") + .method("POST") + .contentTypes(Arrays.asList("application/json")) + .build()); config.put("reservedKeywords", OperationLookupEntry.builder() .path("/reserved-keywords") .method("GET") @@ -36301,6 +36896,7 @@ public class Operations { return OperationConfig.builder() .arrayRequestParameters(value) .inlineEnum(value) + .inlineRequestBody(value) .reservedKeywords(value) ; } @@ -37029,6 +37625,239 @@ public enum InlineEnum200ResponseCategoryEnum { } } } +", + "src/main/java/test/test/runtime/model/InlineRequestBodyRequestContent.java": "/* + * Edge Cases + * + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated. + * Do not edit the class manually. + */ + + +package test.test.runtime.model; + +import java.util.Objects; +import java.util.Arrays; +import com.google.gson.TypeAdapter; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import java.io.IOException; + +import javax.ws.rs.core.GenericType; + +import java.io.IOException; +import java.io.File; +import java.math.BigDecimal; +import java.net.URI; +import java.time.LocalDate; +import java.time.OffsetDateTime; +import java.util.UUID; +import java.lang.reflect.Type; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.List; +import java.util.Set; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonParseException; +import com.google.gson.TypeAdapter; +import com.google.gson.TypeAdapterFactory; +import com.google.gson.reflect.TypeToken; +import com.google.gson.JsonPrimitive; +import com.google.gson.annotations.JsonAdapter; +import com.google.gson.annotations.SerializedName; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; +import com.google.gson.JsonDeserializationContext; +import com.google.gson.JsonDeserializer; +import com.google.gson.JsonSerializationContext; +import com.google.gson.JsonSerializer; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; + +import test.test.runtime.JSON; + +/** + * InlineRequestBodyRequestContent + */ +@lombok.AllArgsConstructor @lombok.experimental.SuperBuilder +public class InlineRequestBodyRequestContent { + public static final String SERIALIZED_NAME_SOME_PROPERTY = "someProperty"; + @SerializedName(SERIALIZED_NAME_SOME_PROPERTY) + private String someProperty; + + public InlineRequestBodyRequestContent() { + } + + public InlineRequestBodyRequestContent someProperty(String someProperty) { + + this.someProperty = someProperty; + return this; + } + + /** + * Get someProperty + * @return someProperty + **/ + @javax.annotation.Nonnull + public String getSomeProperty() { + return someProperty; + } + + + public void setSomeProperty(String someProperty) { + this.someProperty = someProperty; + } + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + InlineRequestBodyRequestContent inlineRequestBodyRequestContent = (InlineRequestBodyRequestContent) o; + return Objects.equals(this.someProperty, inlineRequestBodyRequestContent.someProperty); + + } + + @Override + public int hashCode() { + return Objects.hash(someProperty); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class InlineRequestBodyRequestContent {\\n"); + sb.append(" someProperty: ").append(toIndentedString(someProperty)).append("\\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\\n", "\\n "); + } + + + public static HashSet openapiFields; + public static HashSet openapiRequiredFields; + + static { + // a set of all properties/fields (JSON key names) + openapiFields = new HashSet(); + openapiFields.add("someProperty"); + + // a set of required properties/fields (JSON key names) + openapiRequiredFields = new HashSet(); + openapiRequiredFields.add("someProperty"); + } + + /** + * Validates the JSON Object and throws an exception if issues found + * + * @param jsonObj JSON Object + * @throws IOException if the JSON Object is invalid with respect to InlineRequestBodyRequestContent + */ + public static void validateJsonObject(JsonObject jsonObj) throws IOException { + if (jsonObj == null) { + if (!InlineRequestBodyRequestContent.openapiRequiredFields.isEmpty()) { // has required fields but JSON object is null + throw new IllegalArgumentException(String.format("The required field(s) %s in InlineRequestBodyRequestContent is not found in the empty JSON string", InlineRequestBodyRequestContent.openapiRequiredFields.toString())); + } + } + + Set> entries = jsonObj.entrySet(); + // check to see if the JSON string contains additional fields + for (Entry entry : entries) { + if (!InlineRequestBodyRequestContent.openapiFields.contains(entry.getKey())) { + throw new IllegalArgumentException(String.format("The field \`%s\` in the JSON string is not defined in the \`InlineRequestBodyRequestContent\` properties. JSON: %s", entry.getKey(), jsonObj.toString())); + } + } + + // check to make sure all required properties/fields are present in the JSON string + for (String requiredField : InlineRequestBodyRequestContent.openapiRequiredFields) { + if (jsonObj.get(requiredField) == null) { + throw new IllegalArgumentException(String.format("The required field \`%s\` is not found in the JSON string: %s", requiredField, jsonObj.toString())); + } + } + if (!jsonObj.get("someProperty").isJsonPrimitive()) { + throw new IllegalArgumentException(String.format("Expected the field \`someProperty\` to be a primitive type in the JSON string but got \`%s\`", jsonObj.get("someProperty").toString())); + } + } + + public static class CustomTypeAdapterFactory implements TypeAdapterFactory { + @SuppressWarnings("unchecked") + @Override + public TypeAdapter create(Gson gson, TypeToken type) { + if (!InlineRequestBodyRequestContent.class.isAssignableFrom(type.getRawType())) { + return null; // this class only serializes 'InlineRequestBodyRequestContent' and its subtypes + } + final TypeAdapter elementAdapter = gson.getAdapter(JsonElement.class); + final TypeAdapter thisAdapter + = gson.getDelegateAdapter(this, TypeToken.get(InlineRequestBodyRequestContent.class)); + + return (TypeAdapter) new TypeAdapter() { + @Override + public void write(JsonWriter out, InlineRequestBodyRequestContent value) throws IOException { + JsonObject obj = thisAdapter.toJsonTree(value).getAsJsonObject(); + elementAdapter.write(out, obj); + } + + @Override + public InlineRequestBodyRequestContent read(JsonReader in) throws IOException { + JsonObject jsonObj = elementAdapter.read(in).getAsJsonObject(); + validateJsonObject(jsonObj); + return thisAdapter.fromJsonTree(jsonObj); + } + + }.nullSafe(); + } + } + + /** + * Create an instance of InlineRequestBodyRequestContent given an JSON string + * + * @param jsonString JSON string + * @return An instance of InlineRequestBodyRequestContent + * @throws IOException if the JSON string is invalid with respect to InlineRequestBodyRequestContent + */ + public static InlineRequestBodyRequestContent fromJson(String jsonString) throws IOException { + return JSON.getGson().fromJson(jsonString, InlineRequestBodyRequestContent.class); + } + + /** + * Convert an instance of InlineRequestBodyRequestContent to an JSON string + * + * @return JSON string + */ + public String toJson() { + return JSON.getGson().toJson(this); + } +} ", "src/main/java/test/test/runtime/model/MyEnum.java": "/* * Edge Cases diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/python.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/python.test.ts.snap index 2cabeef82..2ce5932c8 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/python.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/python.test.ts.snap @@ -17430,6 +17430,7 @@ test_project/rest.py docs/DefaultApi.md docs/InlineEnum200Response.md docs/InlineEnum200ResponseCategoryEnum.md +docs/InlineRequestBodyRequestContent.md docs/MyEnum.md README.md test_project/interceptors/try_catch.py @@ -17445,6 +17446,7 @@ test_project/api/__init__.py test_project/models/__init__.py test_project/models/inline_enum200_response.py test_project/models/inline_enum200_response_category_enum.py +test_project/models/inline_request_body_request_content.py test_project/models/my_enum.py", "README.md": "# Edge Cases @@ -17499,12 +17501,14 @@ Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- *DefaultApi* | [**array_request_parameters**](docs/DefaultApi.md#array_request_parameters) | **GET** /array-request-parameters | *DefaultApi* | [**inline_enum**](docs/DefaultApi.md#inline_enum) | **GET** /inline-enum | +*DefaultApi* | [**inline_request_body**](docs/DefaultApi.md#inline_request_body) | **POST** /inline-request-body | *DefaultApi* | [**reserved_keywords**](docs/DefaultApi.md#reserved_keywords) | **GET** /reserved-keywords | ## Documentation For Models - [InlineEnum200Response](docs/InlineEnum200Response.md) - [InlineEnum200ResponseCategoryEnum](docs/InlineEnum200ResponseCategoryEnum.md) + - [InlineRequestBodyRequestContent](docs/InlineRequestBodyRequestContent.md) - [MyEnum](docs/MyEnum.md) ", "docs/DefaultApi.md": "# test_project.DefaultApi @@ -17513,6 +17517,7 @@ Method | HTTP request | Description ------------- | ------------- | ------------- [**array_request_parameters**](DefaultApi.md#array_request_parameters) | **GET** /array-request-parameters | [**inline_enum**](DefaultApi.md#inline_enum) | **GET** /inline-enum | +[**inline_request_body**](DefaultApi.md#inline_request_body) | **POST** /inline-request-body | [**reserved_keywords**](DefaultApi.md#reserved_keywords) | **GET** /reserved-keywords | # **array_request_parameters** @@ -17632,6 +17637,57 @@ This endpoint does not need any parameters. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **inline_request_body** +> inline_request_body(inline_request_body_request_content=inline_request_body_request_content) + + +### Example + +\`\`\`python +import time +import test_project +from test_project.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to http://localhost +# See configuration.py for a list of all supported configuration parameters. +configuration = test_project.Configuration( + host = "http://localhost" +) + +# Enter a context with an instance of the API client +with test_project.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = test_project.DefaultApi(api_client) + inline_request_body_request_content = test_project.InlineRequestBodyRequestContent() # InlineRequestBodyRequestContent | (optional) + + try: + api_instance.inline_request_body(inline_request_body_request_content=inline_request_body_request_content) + except ApiException as e: + print("Exception when calling DefaultApi->inline_request_body: %s\\n" % e) +\`\`\` + +### Parameters +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **inline_request_body_request_content** | [**InlineRequestBodyRequestContent**](InlineRequestBodyRequestContent.md) | | [optional] + +### Return type + +void (empty response body) + +### HTTP request headers + + - **Content-Type**: application/json + - **Accept**: Not defined + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**204** | ok | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **reserved_keywords** > reserved_keywords(var_with=var_with, var_if=var_if, var_class=var_class) @@ -17723,6 +17779,33 @@ Name | Type | Description | Notes [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) +", + "docs/InlineRequestBodyRequestContent.md": "# InlineRequestBodyRequestContent + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**some_property** | **str** | | + +## Example + +\`\`\`python +from test_project.models.inline_request_body_request_content import InlineRequestBodyRequestContent + +# TODO update the JSON string below +json = "{}" +# create an instance of InlineRequestBodyRequestContent from a JSON string +inline_request_body_request_content_instance = InlineRequestBodyRequestContent.from_json(json) +# print the JSON string representation of the object +print(InlineRequestBodyRequestContent.to_json()) + +# convert the object into a dict +inline_request_body_request_content_dict = inline_request_body_request_content_instance.to_dict() +# create an instance of InlineRequestBodyRequestContent from a dict +inline_request_body_request_content_form_dict = inline_request_body_request_content.from_dict(inline_request_body_request_content_dict) +\`\`\` +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + ", "docs/MyEnum.md": "# MyEnum @@ -17803,6 +17886,7 @@ from test_project.exceptions import ApiException # import models into sdk package from test_project.models.inline_enum200_response import InlineEnum200Response from test_project.models.inline_enum200_response_category_enum import InlineEnum200ResponseCategoryEnum +from test_project.models.inline_request_body_request_content import InlineRequestBodyRequestContent from test_project.models.my_enum import MyEnum ", "test_project/api/__init__.py": "# flake8: noqa @@ -17835,6 +17919,7 @@ except ImportError: from typing_extensions import Annotated from test_project.models.inline_enum200_response import InlineEnum200Response +from test_project.models.inline_request_body_request_content import InlineRequestBodyRequestContent from test_project.models.my_enum import MyEnum from test_project.api_client import ApiClient @@ -18457,6 +18542,260 @@ class DefaultApi: + @validate_call + def inline_request_body( + self, + inline_request_body_request_content: Optional[InlineRequestBodyRequestContent] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> None: + """inline_request_body + :param inline_request_body_request_content: (optional) + :type inline_request_body_request_content: InlineRequestBodyRequestContent, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._inline_request_body_serialize( + inline_request_body_request_content=inline_request_body_request_content, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + } + + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ).data + + + @validate_call + def inline_request_body_with_http_info( + self, + inline_request_body_request_content: Optional[InlineRequestBodyRequestContent] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> ApiResponse[None]: + """inline_request_body + :param inline_request_body_request_content: (optional) + :type inline_request_body_request_content: InlineRequestBodyRequestContent, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._inline_request_body_serialize( + inline_request_body_request_content=inline_request_body_request_content, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + } + + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + response_data.read() + return self.api_client.response_deserialize( + response_data=response_data, + response_types_map=_response_types_map, + ) + + + @validate_call + def inline_request_body_without_preload_content( + self, + inline_request_body_request_content: Optional[InlineRequestBodyRequestContent] = None, + _request_timeout: Union[ + None, + Annotated[StrictFloat, Field(gt=0)], + Tuple[ + Annotated[StrictFloat, Field(gt=0)], + Annotated[StrictFloat, Field(gt=0)] + ] + ] = None, + _request_auth: Optional[Dict[StrictStr, Any]] = None, + _content_type: Optional[StrictStr] = None, + _headers: Optional[Dict[StrictStr, Any]] = None, + _host_index: Annotated[StrictInt, Field(ge=0, le=0)] = 0, + ) -> RESTResponseType: + """inline_request_body + :param inline_request_body_request_content: (optional) + :type inline_request_body_request_content: InlineRequestBodyRequestContent, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :type _request_timeout: int, tuple(int, int), optional + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the + authentication in the spec for a single request. + :type _request_auth: dict, optional + :param _content_type: force content-type for the request. + :type _content_type: str, Optional + :param _headers: set to override the headers for a single + request; this effectively ignores the headers + in the spec for a single request. + :type _headers: dict, optional + :param _host_index: set to override the host_index for a single + request; this effectively ignores the host_index + in the spec for a single request. + :type _host_index: int, optional + :return: Returns the result object. + """ # noqa: E501 + + _param = self._inline_request_body_serialize( + inline_request_body_request_content=inline_request_body_request_content, + _request_auth=_request_auth, + _content_type=_content_type, + _headers=_headers, + _host_index=_host_index + ) + + _response_types_map: Dict[str, Optional[str]] = { + } + + response_data = self.api_client.call_api( + *_param, + _request_timeout=_request_timeout + ) + return response_data.response + + + def _inline_request_body_serialize( + self, + inline_request_body_request_content, + _request_auth, + _content_type, + _headers, + _host_index, + ) -> Tuple: + + _host = None + + _collection_formats: Dict[str, str] = { + } + + _path_params: Dict[str, str] = {} + _query_params: List[Tuple[str, str]] = [] + _header_params: Dict[str, Optional[str]] = _headers or {} + _form_params: List[Tuple[str, str]] = [] + _files: Dict[str, str] = {} + _body_params: Optional[bytes] = None + + # process the path parameters + # process the query parameters + # process the header parameters + # process the form parameters + # process the body parameter + if inline_request_body_request_content is not None: + _body_params = inline_request_body_request_content + + + + # set the HTTP header \`Content-Type\` + if _content_type: + _header_params['Content-Type'] = _content_type + else: + _default_content_type = ( + self.api_client.select_header_content_type( + [ + 'application/json' + ] + ) + ) + if _default_content_type is not None: + _header_params['Content-Type'] = _default_content_type + + # authentication setting + _auth_settings: List[str] = [ + ] + + return self.api_client.param_serialize( + method='POST', + resource_path='/inline-request-body', + path_params=_path_params, + query_params=_query_params, + header_params=_header_params, + body=_body_params, + post_params=_form_params, + files=_files, + auth_settings=_auth_settings, + collection_formats=_collection_formats, + _host=_host, + _request_auth=_request_auth + ) + + + @validate_call def reserved_keywords( self, @@ -18747,6 +19086,7 @@ T = TypeVar('T') class OperationConfig(Generic[T]): array_request_parameters: T inline_enum: T + inline_request_body: T reserved_keywords: T ... @@ -18762,6 +19102,11 @@ OperationLookup = { "method": "GET", "contentTypes": ["application/json"] }, + "inline_request_body": { + "path": "/inline-request-body", + "method": "POST", + "contentTypes": ["application/json"] + }, "reserved_keywords": { "path": "/reserved-keywords", "method": "GET", @@ -19180,6 +19525,122 @@ def inline_enum_handler(_handler: InlineEnumHandlerFunction = None, interceptors else: raise Exception("Positional arguments are not supported by inline_enum_handler.") +class InlineRequestBodyRequestParameters(BaseModel): + """ + Query, path and header parameters for the InlineRequestBody operation + """ + + class Config: + """Pydantic configuration""" + populate_by_name = True + validate_assignment = True + + def to_json(self) -> str: + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> InlineRequestBodyRequestParameters: + return cls.from_dict(json.loads(json_str)) + + def to_dict(self): + return self.model_dump(exclude={}, exclude_none=True) + + @classmethod + def from_dict(cls, obj: dict) -> InlineRequestBodyRequestParameters: + if obj is None: + return None + return InlineRequestBodyRequestParameters.model_validate(obj) + + +# Request body type (default to Any when no body parameters exist, or leave unchanged as str if it's a primitive type) +InlineRequestBodyRequestBody = InlineRequestBodyRequestContent + +InlineRequestBody204OperationResponse = ApiResponse[Literal[204], None] + +InlineRequestBodyOperationResponses = Union[InlineRequestBody204OperationResponse, ] + +# Request type for inline_request_body +InlineRequestBodyRequest = ApiRequest[InlineRequestBodyRequestParameters, InlineRequestBodyRequestBody] +InlineRequestBodyChainedRequest = ChainedApiRequest[InlineRequestBodyRequestParameters, InlineRequestBodyRequestBody] + +class InlineRequestBodyHandlerFunction(Protocol): + def __call__(self, input: InlineRequestBodyRequest, **kwargs) -> InlineRequestBodyOperationResponses: + ... + +InlineRequestBodyInterceptor = Callable[[InlineRequestBodyChainedRequest], InlineRequestBodyOperationResponses] + +def inline_request_body_handler(_handler: InlineRequestBodyHandlerFunction = None, interceptors: List[InlineRequestBodyInterceptor] = []): + """ + Decorator for an api handler for the inline_request_body operation, providing a typed interface for inputs and outputs + """ + def _handler_wrapper(handler: InlineRequestBodyHandlerFunction): + @wraps(handler) + def wrapper(event, context, additional_interceptors = [], **kwargs): + all_interceptors = additional_interceptors + interceptors + + raw_string_parameters = decode_request_parameters({ + **(event.get('pathParameters', {}) or {}), + **(event.get('queryStringParameters', {}) or {}), + **(event.get('headers', {}) or {}), + }) + raw_string_array_parameters = decode_request_parameters({ + **(event.get('multiValueQueryStringParameters', {}) or {}), + **(event.get('multiValueHeaders', {}) or {}), + }) + + def response_headers_for_status_code(status_code): + headers_for_status = {} + return headers_for_status + + request_parameters = None + try: + request_parameters = InlineRequestBodyRequestParameters.from_dict({ + }) + except Exception as e: + return { + 'statusCode': 400, + 'headers': {**response_headers_for_status_code(400), **extract_response_headers_from_interceptors(all_interceptors)}, + 'body': '{"message": "' + str(e) + '"}', + } + + # Non-primitive type so parse the body into the appropriate model + body = parse_body(event['body'], ['application/json'], InlineRequestBodyRequestBody) + interceptor_context = { + "operationId": "inline_request_body", + } + + chain = _build_handler_chain(all_interceptors, handler) + response = chain.next(ApiRequest( + request_parameters, + body, + event, + context, + interceptor_context, + ), **kwargs) + + response_headers = {** (response.headers or {}), **response_headers_for_status_code(response.status_code)} + response_body = '' + if response.body is None: + pass + elif response.status_code == 204: + response_body = response.body + + return { + 'statusCode': response.status_code, + 'headers': response_headers, + 'multiValueHeaders': response.multi_value_headers or {}, + 'body': response_body, + } + return wrapper + + # Support use as a decorator with no arguments, or with interceptor arguments + if callable(_handler): + return _handler_wrapper(_handler) + elif _handler is None: + return _handler_wrapper + else: + raise Exception("Positional arguments are not supported by inline_request_body_handler.") + class ReservedKeywordsRequestParameters(BaseModel): """ Query, path and header parameters for the ReservedKeywords operation @@ -19312,6 +19773,7 @@ OperationIdByMethodAndPath = { concat_method_and_path(method_and_path["method"], class HandlerRouterHandlers: array_request_parameters: Callable[[Dict, Any], Dict] inline_enum: Callable[[Dict, Any], Dict] + inline_request_body: Callable[[Dict, Any], Dict] reserved_keywords: Callable[[Dict, Any], Dict] def handler_router(handlers: HandlerRouterHandlers, interceptors: List[Interceptor] = []): @@ -20883,6 +21345,7 @@ def try_catch_interceptor(request: ChainedApiRequest) -> ApiResponse: # import models into model package from test_project.models.inline_enum200_response import InlineEnum200Response from test_project.models.inline_enum200_response_category_enum import InlineEnum200ResponseCategoryEnum +from test_project.models.inline_request_body_request_content import InlineRequestBodyRequestContent from test_project.models.my_enum import MyEnum ", "test_project/models/inline_enum200_response.py": "# coding: utf-8 @@ -21024,6 +21487,95 @@ class InlineEnum200ResponseCategoryEnum(str, Enum): +", + "test_project/models/inline_request_body_request_content.py": "# coding: utf-8 + +""" + Edge Cases + + No description provided + + The version of the OpenAPI document: 1.0.0 + + NOTE: This class is auto generated. + Do not edit the class manually. +""" # noqa: E501 + +from __future__ import annotations +import pprint +import re # noqa: F401 +import json +from enum import Enum +from datetime import date, datetime +from typing import Any, List, Union, ClassVar, Dict, Optional, TYPE_CHECKING +from pydantic import Field, StrictStr, ValidationError, field_validator, BaseModel, SecretStr, StrictFloat, StrictInt, StrictBytes, StrictBool +from decimal import Decimal +from typing_extensions import Annotated, Literal +try: + from typing import Self +except ImportError: + from typing_extensions import Self + +class InlineRequestBodyRequestContent(BaseModel): + """ + InlineRequestBodyRequestContent + """ # noqa: E501 + some_property: StrictStr = Field(alias="someProperty") + __properties: ClassVar[List[str]] = ["someProperty"] + + + model_config = { + "populate_by_name": True, + "validate_assignment": True + } + + def to_str(self) -> str: + """Returns the string representation of the model using alias""" + return pprint.pformat(self.model_dump(by_alias=True)) + + def to_json(self) -> str: + """Returns the JSON representation of the model using alias""" + # TODO: pydantic v2: use .model_dump_json(by_alias=True, exclude_unset=True) instead + return json.dumps(self.to_dict()) + + @classmethod + def from_json(cls, json_str: str) -> Self: + """Create an instance of InlineRequestBodyRequestContent from a JSON string""" + return cls.from_dict(json.loads(json_str)) + + def to_dict(self) -> Dict[str, Any]: + """Return the dictionary representation of the model using alias. + + This has the following differences from calling pydantic's + \`self.model_dump(by_alias=True)\`: + + * \`None\` is only added to the output dict for nullable fields that + were set at model initialization. Other fields with value \`None\` + are ignored. + """ + _dict = self.model_dump( + by_alias=True, + exclude={ + }, + exclude_none=True, + ) + return _dict + + @classmethod + def from_dict(cls, obj: Dict) -> Self: + """Create an instance of InlineRequestBodyRequestContent from a dict""" + + if obj is None: + return None + + if not isinstance(obj, dict): + return cls.model_validate(obj) + + _obj = cls.model_validate({ + "someProperty": obj.get("someProperty") + }) + return _obj + ", "test_project/models/my_enum.py": "# coding: utf-8 diff --git a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript.test.ts.snap b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript.test.ts.snap index 94763aefe..0369e72a1 100644 --- a/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript.test.ts.snap +++ b/packages/type-safe-api/test/scripts/generators/__snapshots__/typescript.test.ts.snap @@ -8239,6 +8239,7 @@ src/models/index.ts src/models/model-utils.ts src/models/InlineEnum200Response.ts src/models/InlineEnum200ResponseCategoryEnum.ts +src/models/InlineRequestBodyRequestContent.ts src/models/MyEnum.ts", "src/apis/DefaultApi.ts": "/* tslint:disable */ /* eslint-disable */ @@ -8256,11 +8257,14 @@ src/models/MyEnum.ts", import * as runtime from '../runtime'; import type { InlineEnum200Response, + InlineRequestBodyRequestContent, MyEnum, } from '../models'; import { InlineEnum200ResponseFromJSON, InlineEnum200ResponseToJSON, + InlineRequestBodyRequestContentFromJSON, + InlineRequestBodyRequestContentToJSON, MyEnumFromJSON, MyEnumToJSON, } from '../models'; @@ -8278,6 +8282,10 @@ export interface ArrayRequestParametersRequest { } +export interface InlineRequestBodyRequest { + inlineRequestBodyRequestContent?: InlineRequestBodyRequestContent; +} + export interface ReservedKeywordsRequest { _with?: string; _if?: string; @@ -8381,6 +8389,36 @@ export class DefaultApi extends runtime.BaseAPI { return await response.value(); } + /** + * + */ + async inlineRequestBodyRaw(requestParameters: InlineRequestBodyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise> { + const queryParameters: any = {}; + + + const headerParameters: runtime.HTTPHeaders = {}; + + headerParameters['Content-Type'] = 'application/json'; + + + const response = await this.request({ + path: \`/inline-request-body\`, + method: 'POST', + headers: headerParameters, + query: queryParameters, + body: InlineRequestBodyRequestContentToJSON(requestParameters.inlineRequestBodyRequestContent), + }, initOverrides); + + return new runtime.VoidApiResponse(response); + } + + /** + * + */ + async inlineRequestBody(requestParameters: InlineRequestBodyRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise { + await this.inlineRequestBodyRaw(requestParameters, initOverrides); + } + /** * */ @@ -8432,6 +8470,9 @@ import { InlineEnum200ResponseCategoryEnum, InlineEnum200ResponseCategoryEnumFromJSON, InlineEnum200ResponseCategoryEnumToJSON, + InlineRequestBodyRequestContent, + InlineRequestBodyRequestContentFromJSON, + InlineRequestBodyRequestContentToJSON, MyEnum, MyEnumFromJSON, MyEnumToJSON, @@ -8439,6 +8480,7 @@ import { // Import request parameter interfaces import { ArrayRequestParametersRequest, + InlineRequestBodyRequest, ReservedKeywordsRequest, } from '..'; @@ -8449,6 +8491,7 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda export interface OperationConfig { arrayRequestParameters: T; inlineEnum: T; + inlineRequestBody: T; reservedKeywords: T; } @@ -8464,6 +8507,11 @@ export const OperationLookup = { method: 'GET', contentTypes: ['application/json'], }, + inlineRequestBody: { + path: '/inline-request-body', + method: 'POST', + contentTypes: ['application/json'], + }, reservedKeywords: { path: '/reserved-keywords', method: 'GET', @@ -8585,7 +8633,7 @@ const extractResponseHeadersFromInterceptors = (interceptors: any[]): { [key: st }), {} as { [key: string]: string }); }; -export type OperationIds = | 'arrayRequestParameters' | 'inlineEnum' | 'reservedKeywords'; +export type OperationIds = | 'arrayRequestParameters' | 'inlineEnum' | 'inlineRequestBody' | 'reservedKeywords'; export type OperationApiGatewayProxyResult = APIGatewayProxyResult & { __operationId?: T }; // Api gateway lambda handler type @@ -8896,6 +8944,114 @@ export const inlineEnumHandler = ( body: response.body ? marshal(response.statusCode, response.body) : '', }; }; +/** + * Path, Query and Header parameters for InlineRequestBody + */ +export interface InlineRequestBodyRequestParameters { +} + +/** + * Request body parameter for InlineRequestBody + */ +export type InlineRequestBodyRequestBody = InlineRequestBodyRequestContent; + +export type InlineRequestBody204OperationResponse = OperationResponse<204, undefined>; + +export type InlineRequestBodyOperationResponses = | InlineRequestBody204OperationResponse ; + +// Type that the handler function provided to the wrapper must conform to +export type InlineRequestBodyHandlerFunction = LambdaHandlerFunction; +export type InlineRequestBodyChainedHandlerFunction = ChainedLambdaHandlerFunction; +export type InlineRequestBodyChainedRequestInput = ChainedRequestInput; + +/** + * Lambda handler wrapper to provide typed interface for the implementation of inlineRequestBody + */ +export const inlineRequestBodyHandler = ( + ...handlers: [InlineRequestBodyChainedHandlerFunction, ...InlineRequestBodyChainedHandlerFunction[]] +): OperationApiGatewayLambdaHandler<'inlineRequestBody'> => async (event: any, context: any, _callback?: any, additionalInterceptors: InlineRequestBodyChainedHandlerFunction[] = []): Promise => { + const operationId = "inlineRequestBody"; + + const rawSingleValueParameters = decodeRequestParameters({ + ...(event.pathParameters || {}), + ...(event.queryStringParameters || {}), + ...(event.headers || {}), + }) as { [key: string]: string | undefined }; + const rawMultiValueParameters = decodeRequestParameters({ + ...(event.multiValueQueryStringParameters || {}), + ...(event.multiValueHeaders || {}), + }) as { [key: string]: string[] | undefined }; + + const marshal = (statusCode: number, responseBody: any): string => { + let marshalledBody = responseBody; + switch(statusCode) { + case 204: + break; + default: + break; + } + + return marshalledBody; + }; + + const errorHeaders = (statusCode: number): { [key: string]: string } => { + let headers = {}; + + switch(statusCode) { + default: + break; + } + + return headers; + }; + + let requestParameters: InlineRequestBodyRequestParameters | undefined = undefined; + + try { + requestParameters = { + + }; + } catch (e: any) { + const res = { + statusCode: 400, + body: { message: e.message }, + headers: extractResponseHeadersFromInterceptors(handlers), + }; + return { + ...res, + headers: { + ...errorHeaders(res.statusCode), + ...res.headers, + }, + body: res.body ? marshal(res.statusCode, res.body) : '', + }; + } + + const demarshal = (bodyString: string): any => { + return InlineRequestBodyRequestContentFromJSON(JSON.parse(bodyString)); + }; + const body = parseBody(event.body, demarshal, ['application/json']) as InlineRequestBodyRequestBody; + + const chain = buildHandlerChain(...additionalInterceptors, ...handlers); + const response = await chain.next({ + input: { + requestParameters, + body, + }, + event, + context, + interceptorContext: { operationId }, + }); + + return { + ...response, + headers: { + ...errorHeaders(response.statusCode), + ...response.headers, + }, + body: response.body ? marshal(response.statusCode, response.body) : '', + }; +}; /** * Path, Query and Header parameters for ReservedKeywords */ @@ -9014,12 +9170,13 @@ export const reservedKeywordsHandler = ( export interface HandlerRouterHandlers { readonly arrayRequestParameters: OperationApiGatewayLambdaHandler<'arrayRequestParameters'>; readonly inlineEnum: OperationApiGatewayLambdaHandler<'inlineEnum'>; + readonly inlineRequestBody: OperationApiGatewayLambdaHandler<'inlineRequestBody'>; readonly reservedKeywords: OperationApiGatewayLambdaHandler<'reservedKeywords'>; } -export type AnyOperationRequestParameters = | ArrayRequestParametersRequestParameters| InlineEnumRequestParameters| ReservedKeywordsRequestParameters; -export type AnyOperationRequestBodies = | ArrayRequestParametersRequestBody| InlineEnumRequestBody| ReservedKeywordsRequestBody; -export type AnyOperationResponses = | ArrayRequestParametersOperationResponses| InlineEnumOperationResponses| ReservedKeywordsOperationResponses; +export type AnyOperationRequestParameters = | ArrayRequestParametersRequestParameters| InlineEnumRequestParameters| InlineRequestBodyRequestParameters| ReservedKeywordsRequestParameters; +export type AnyOperationRequestBodies = | ArrayRequestParametersRequestBody| InlineEnumRequestBody| InlineRequestBodyRequestBody| ReservedKeywordsRequestBody; +export type AnyOperationResponses = | ArrayRequestParametersOperationResponses| InlineEnumOperationResponses| InlineRequestBodyOperationResponses| ReservedKeywordsOperationResponses; export interface HandlerRouterProps< RequestParameters, @@ -9473,6 +9630,72 @@ export function InlineEnum200ResponseCategoryEnumToJSON(value?: InlineEnum200Res return value; } +", + "src/models/InlineRequestBodyRequestContent.ts": "/* tslint:disable */ +/* eslint-disable */ +/** + * Edge Cases + * + * + * The version of the OpenAPI document: 1.0.0 + * + * + * NOTE: This class is auto generated. + * Do not edit the class manually. + */ +import { exists, mapValues } from './model-utils'; + +/** + * + * @export + * @interface InlineRequestBodyRequestContent + */ +export interface InlineRequestBodyRequestContent { + /** + * + * @type {string} + * @memberof InlineRequestBodyRequestContent + */ + someProperty: string; +} + + +/** + * Check if a given object implements the InlineRequestBodyRequestContent interface. + */ +export function instanceOfInlineRequestBodyRequestContent(value: object): boolean { + let isInstance = true; + isInstance = isInstance && "someProperty" in value; + return isInstance; +} + +export function InlineRequestBodyRequestContentFromJSON(json: any): InlineRequestBodyRequestContent { + return InlineRequestBodyRequestContentFromJSONTyped(json, false); +} + +export function InlineRequestBodyRequestContentFromJSONTyped(json: any, ignoreDiscriminator: boolean): InlineRequestBodyRequestContent { + if ((json === undefined) || (json === null)) { + return json; + } + return { + + 'someProperty': json['someProperty'], + }; +} + +export function InlineRequestBodyRequestContentToJSON(value?: InlineRequestBodyRequestContent | null): any { + if (value === undefined) { + return undefined; + } + if (value === null) { + return null; + } + return { + + 'someProperty': value.someProperty, + }; +} + ", "src/models/MyEnum.ts": "/* tslint:disable */ /* eslint-disable */ @@ -9518,6 +9741,7 @@ export function MyEnumToJSON(value?: MyEnum | null): any { /* eslint-disable */ export * from './InlineEnum200Response'; export * from './InlineEnum200ResponseCategoryEnum'; +export * from './InlineRequestBodyRequestContent'; export * from './MyEnum'; ", "src/models/model-utils.ts": "/* tslint:disable */