Skip to content

Commit

Permalink
feat: support request body encoding option (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
Himenon committed Apr 1, 2023
1 parent 3530287 commit 025d53e
Show file tree
Hide file tree
Showing 21 changed files with 2,704 additions and 4 deletions.
53 changes: 53 additions & 0 deletions src/code-templates/_shared/ApiClientInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,50 @@ const createObjectLikeInterface = (factory: TsGenerator.Factory.Type) => {
});
};

const createEncodingInterface = (factory: TsGenerator.Factory.Type) => {
return factory.InterfaceDeclaration.create({
export: true,
name: "Encoding",
members: [
factory.PropertySignature.create({
name: "contentType",
optional: true,
type: factory.TypeReferenceNode.create({
name: "string",
}),
}),
factory.PropertySignature.create({
name: "headers",
optional: true,
type: factory.TypeReferenceNode.create({
name: "Record<string, any>",
}),
}),
factory.PropertySignature.create({
name: "style",
optional: true,
type: factory.TypeReferenceNode.create({
name: "string",
}),
}),
factory.PropertySignature.create({
name: "explode",
optional: true,
type: factory.TypeReferenceNode.create({
name: "boolean",
}),
}),
factory.PropertySignature.create({
name: "allowReserved",
optional: true,
type: factory.TypeReferenceNode.create({
name: "boolean",
}),
}),
],
});
};

export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Params[], option: Option): ts.Statement[] => {
const objectLikeOrAnyType = factory.UnionTypeNode.create({
typeNodes: [
Expand All @@ -117,12 +161,15 @@ export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Pa
],
});

const encodingInterface = createEncodingInterface(factory);

const requestArgs = factory.ParameterDeclaration.create({
name: "requestArgs",
type: factory.TypeReferenceNode.create({
name: "RequestArgs",
}),
});

const options = factory.ParameterDeclaration.create({
name: "options",
optional: true,
Expand Down Expand Up @@ -197,6 +244,11 @@ export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Pa
optional: false,
type: objectLikeOrAnyType,
}),
factory.PropertySignature.create({
name: `requestBodyEncoding`,
optional: true,
type: factory.TypeReferenceNode.create({ name: "Record<string, Encoding>" }),
}),
factory.PropertySignature.create({
name: `queryParameters`,
optional: false,
Expand All @@ -219,6 +271,7 @@ export const create = (factory: TsGenerator.Factory.Type, list: CodeGenerator.Pa
...createQueryParamsDeclarations(factory),
createSuccessResponseTypeAlias("SuccessResponses", factory, successResponseNames),
errorResponseNamespace,
encodingInterface,
requestArgsInterfaceDeclaration,
factory.InterfaceDeclaration.create({
export: true,
Expand Down
22 changes: 22 additions & 0 deletions src/code-templates/_shared/MethodBody/CallRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,24 @@ export interface Params {
hasRequestBody: boolean;
}

/**
*
* const encodingMap = {
* "application/json": {},
* "application/x-www-form-urlencoded": {},
* }
*/
const createEncodingParams = (factory: TsGenerator.Factory.Type, params: CodeGenerator.Params): ts.Expression => {
const content = params.operationParams.requestBody?.content;
if (!content) {
return factory.Identifier.create({ name: "undefined" });
}
if (params.convertedParams.has2OrMoreRequestContentTypes) {
return factory.Identifier.create({ name: `requestEncodings[params.headers["Content-Type"]]` });
}
return factory.Identifier.create({ name: `requestEncodings["${params.convertedParams.requestFirstContentType}"]` });
};

/**
* this.apiClient.request("GET", url, requestBody, headers, queryParameters);
*/
Expand Down Expand Up @@ -41,6 +59,10 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
? Utils.generateVariableIdentifier(factory, "params.requestBody")
: factory.Identifier.create({ name: "undefined" }),
}),
factory.PropertyAssignment.create({
name: "requestBodyEncoding",
initializer: createEncodingParams(factory, params),
}),
factory.PropertyAssignment.create({
name: "queryParameters",
initializer: convertedParams.hasQueryParameters
Expand Down
47 changes: 46 additions & 1 deletion src/code-templates/_shared/MethodBody/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,26 @@ import * as HeaderParameter from "./HeaderParameter";
import * as PathParameter from "./PathParameter";
import * as QueryParameter from "./QueryParameter";
import type { MethodType } from "./types";
import { Encoding } from "../../../typedef/OpenApi";

export interface Params$GenerateUrl {
urlTemplate: Utils.Params$TemplateExpression;
}

type EncodingMap = Record<string, Encoding>;

export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.Params, methodType: MethodType): ts.Statement[] => {
const statements: ts.Statement[] = [];
const { convertedParams } = params;
const { convertedParams, operationParams } = params;
const { pickedParameters } = convertedParams;

// Generate Path Parameter
const pathParameters = pickedParameters.filter(PathParameter.isPathParameter);
statements.push(PathParameter.create(factory, params.operationParams.requestUri, pathParameters, methodType));

/**
* Create Variable: const header = {};
*/
const initialHeaderObject: Utils.LiteralExpressionObject = {};
if (convertedParams.has2OrMoreRequestContentTypes) {
initialHeaderObject["Content-Type"] = {
Expand Down Expand Up @@ -59,6 +65,45 @@ export const create = (factory: TsGenerator.Factory.Type, params: CodeGenerator.
}),
);

/**
* Create Variable: const requestEncoding = {};
*/
const content = operationParams.requestBody?.content;
if (content) {
const encodingMap = Object.keys(content).reduce<EncodingMap>((all, key) => {
const { encoding } = content[key];
if (!encoding) {
return all;
}
return { ...all, [key]: encoding };
}, {});
let identifier: ts.Identifier | undefined;
if (convertedParams.has2OrMoreRequestContentTypes) {
identifier = factory.Identifier.create({
name: JSON.stringify(encodingMap, null, 2),
});
} else if (convertedParams.requestFirstContentType) {
identifier = factory.Identifier.create({
name: JSON.stringify({ [convertedParams.requestFirstContentType]: encodingMap[convertedParams.requestFirstContentType] }, null, 2),
});
}
const requestEncodingsVariableStatement = factory.VariableStatement.create({
declarationList: factory.VariableDeclarationList.create({
flag: "const",
declarations: [
factory.VariableDeclaration.create({
name: "requestEncodings",
initializer: identifier,
}),
],
}),
});

if (identifier && Object.keys(encodingMap).length > 0) {
statements.push(requestEncodingsVariableStatement);
}
}

// Generate Query Parameter
if (convertedParams.hasQueryParameters) {
const queryParameter = pickedParameters.filter(item => item.in === "query");
Expand Down
2 changes: 1 addition & 1 deletion src/meta.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export const Name = "@himenon/openapi-typescript-code-generator";
export const Version = "0.23.0";
export const Version = "0.23.0";
20 changes: 20 additions & 0 deletions test/__tests__/class/__snapshots__/argo-rollout-test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3826,11 +3826,19 @@ export namespace ErrorResponse {
export type RolloutService_UndoRollout = void;
export type RolloutService_Version = void;
}
export interface Encoding {
contentType?: string;
headers?: Record<string, any>;
style?: string;
explode?: boolean;
allowReserved?: boolean;
}
export interface RequestArgs {
httpMethod: HttpMethod;
url: string;
headers: ObjectLike | any;
requestBody: ObjectLike | any;
requestBodyEncoding?: Record<string, Encoding>;
queryParameters: QueryParameters | undefined;
}
export interface ApiClient<RequestOption> {
Expand All @@ -3849,6 +3857,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand All @@ -3862,6 +3871,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand All @@ -3875,6 +3885,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand All @@ -3889,6 +3900,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3902,6 +3914,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand All @@ -3915,6 +3928,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand All @@ -3929,6 +3943,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3943,6 +3958,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3957,6 +3973,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3971,6 +3988,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3985,6 +4003,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: params.requestBody,
requestBodyEncoding: requestEncodings["application/json"],
queryParameters: undefined
}, option);
}
Expand All @@ -3998,6 +4017,7 @@ export class Client<RequestOption> {
url: url,
headers: headers,
requestBody: undefined,
requestBodyEncoding: undefined,
queryParameters: undefined
}, option);
}
Expand Down
8 changes: 8 additions & 0 deletions test/__tests__/class/__snapshots__/format.domain.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,19 @@ export interface QueryParameters {
}
export type SuccessResponses = void;
export namespace ErrorResponse { }
export interface Encoding {
contentType?: string;
headers?: Record<string, any>;
style?: string;
explode?: boolean;
allowReserved?: boolean;
}
export interface RequestArgs {
httpMethod: HttpMethod;
url: string;
headers: ObjectLike | any;
requestBody: ObjectLike | any;
requestBodyEncoding?: Record<string, Encoding>;
queryParameters: QueryParameters | undefined;
}
export interface ApiClient<RequestOption> {
Expand Down

0 comments on commit 025d53e

Please sign in to comment.