diff --git a/package.json b/package.json index d820540d9..02bbf2e84 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "openapi-typescript-codegen", + "name": "@baking-bad/openapi-typescript-codegen", "version": "0.9.3", "description": "Library that generates Typescript clients based on the OpenAPI specification.", "author": "Ferdi Koomen", diff --git a/src/openApi/v2/parser/getOperationPath.ts b/src/openApi/v2/parser/getOperationPath.ts index 7d2a07cff..d4357ad9a 100644 --- a/src/openApi/v2/parser/getOperationPath.ts +++ b/src/openApi/v2/parser/getOperationPath.ts @@ -12,5 +12,5 @@ export function getOperationPath(path: string): string { .replace(/\{(.*?)\}/g, (_, w: string) => { return `\${${getOperationParameterName(w)}}`; }) - .replace('${apiVersion}', '${OpenAPI.VERSION}'); + .replace('${apiVersion}', '${this.config.version}'); } diff --git a/src/openApi/v3/parser/getOperationPath.ts b/src/openApi/v3/parser/getOperationPath.ts index 7d2a07cff..d4357ad9a 100644 --- a/src/openApi/v3/parser/getOperationPath.ts +++ b/src/openApi/v3/parser/getOperationPath.ts @@ -12,5 +12,5 @@ export function getOperationPath(path: string): string { .replace(/\{(.*?)\}/g, (_, w: string) => { return `\${${getOperationParameterName(w)}}`; }) - .replace('${apiVersion}', '${OpenAPI.VERSION}'); + .replace('${apiVersion}', '${this.config.version}'); } diff --git a/src/templates/core/ApiOptions.hbs b/src/templates/core/ApiOptions.hbs new file mode 100644 index 000000000..fad75e957 --- /dev/null +++ b/src/templates/core/ApiOptions.hbs @@ -0,0 +1,23 @@ +{{>header}} + +import type { Resolver, Headers } from './ApiRequestOptions'; + +export type ApiOptions = { + baseUrl: string; + version: string; + withCredentials: boolean; + token?: string | Resolver; + username?: string | Resolver; + password?: string | Resolver; + defaultHeaders?: Headers | Resolver; +} + +export const DefaultApiOptions: ApiOptions = { + baseUrl: '{{{server}}}', + version: '{{{version}}}', + withCredentials: false, + token: undefined, + username: undefined, + password: undefined, + defaultHeaders: undefined, +}; diff --git a/src/templates/core/ApiRequestOptions.hbs b/src/templates/core/ApiRequestOptions.hbs index 76251eac4..d7678d9f3 100644 --- a/src/templates/core/ApiRequestOptions.hbs +++ b/src/templates/core/ApiRequestOptions.hbs @@ -1,6 +1,16 @@ {{>header}} +export type Resolver = (options: ApiRequestOptions) => Promise; +export type Headers = Record; + export type ApiRequestOptions = { + readonly baseUrl: string; + readonly withCredentials?: boolean; + readonly version: string; + readonly token?: string | Resolver; + readonly username?: string | Resolver; + readonly password?: string | Resolver; + readonly defaultHeaders?: Headers | Resolver; readonly method: 'GET' | 'PUT' | 'POST' | 'DELETE' | 'OPTIONS' | 'HEAD' | 'PATCH'; readonly path: string; readonly cookies?: Record; diff --git a/src/templates/core/OpenAPI.hbs b/src/templates/core/OpenAPI.hbs deleted file mode 100644 index 2b59a9708..000000000 --- a/src/templates/core/OpenAPI.hbs +++ /dev/null @@ -1,26 +0,0 @@ -{{>header}} - -import type { ApiRequestOptions } from './ApiRequestOptions'; - -type Resolver = (options: ApiRequestOptions) => Promise; -type Headers = Record; - -type Config = { - BASE: string; - VERSION: string; - WITH_CREDENTIALS: boolean; - TOKEN?: string | Resolver; - USERNAME?: string | Resolver; - PASSWORD?: string | Resolver; - HEADERS?: Headers | Resolver; -} - -export const OpenAPI: Config = { - BASE: '{{{server}}}', - VERSION: '{{{version}}}', - WITH_CREDENTIALS: false, - TOKEN: undefined, - USERNAME: undefined, - PASSWORD: undefined, - HEADERS: undefined, -}; diff --git a/src/templates/core/fetch/getHeaders.hbs b/src/templates/core/fetch/getHeaders.hbs index 3d1a62c7e..88a728c38 100644 --- a/src/templates/core/fetch/getHeaders.hbs +++ b/src/templates/core/fetch/getHeaders.hbs @@ -1,8 +1,8 @@ async function getHeaders(options: ApiRequestOptions): Promise { - const token = await resolve(options, OpenAPI.TOKEN); - const username = await resolve(options, OpenAPI.USERNAME); - const password = await resolve(options, OpenAPI.PASSWORD); - const defaultHeaders = await resolve(options, OpenAPI.HEADERS); + const token = await resolve(options, options.token); + const username = await resolve(options, options.username); + const password = await resolve(options, options.password); + const defaultHeaders = await resolve(options, options.headers); const headers = new Headers({ Accept: 'application/json', diff --git a/src/templates/core/fetch/request.hbs b/src/templates/core/fetch/request.hbs index c22330e51..ea971bc9c 100644 --- a/src/templates/core/fetch/request.hbs +++ b/src/templates/core/fetch/request.hbs @@ -3,7 +3,6 @@ import { ApiError } from './ApiError'; import type { ApiRequestOptions } from './ApiRequestOptions'; import type { ApiResult } from './ApiResult'; -import { OpenAPI } from './OpenAPI'; {{>functions/isDefined}} diff --git a/src/templates/core/fetch/sendRequest.hbs b/src/templates/core/fetch/sendRequest.hbs index 4afd07317..5c086df6f 100644 --- a/src/templates/core/fetch/sendRequest.hbs +++ b/src/templates/core/fetch/sendRequest.hbs @@ -4,7 +4,7 @@ async function sendRequest(options: ApiRequestOptions, url: string): Promise): string { value.forEach(value => { qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`); }); + } else if (typeof value === 'object') { + switch (key) { + case 'anyof': { + qs.push(`${encodeURIComponent(key)}`); + if (value.fields) { + qs.push(`.${encodeURIComponent(Array(value.fileds).join('.'))}`); + } + qs.push(`=`); + if (value.value) { + qs.push(`${encodeURIComponent(value.value)}`); + } + } + default: { + Object.entries(value).map(raw => { + let val = ''; + if (raw[1] instanceof Date) { + val = (raw[1] as Date).toISOString(); + } else if (Array.isArray(raw[1])) { + val = Array(raw[1]).join(','); + } else { + val = String(raw[1]); + } + qs.push(`${encodeURIComponent(key)}.${encodeURIComponent(String(raw[0]))}=${encodeURIComponent(val)}`); + }); + } + } } else { qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`); } diff --git a/src/templates/core/functions/getUrl.hbs b/src/templates/core/functions/getUrl.hbs index be040bbb6..f4bfe2e80 100644 --- a/src/templates/core/functions/getUrl.hbs +++ b/src/templates/core/functions/getUrl.hbs @@ -1,6 +1,6 @@ function getUrl(options: ApiRequestOptions): string { const path = options.path.replace(/[:]/g, '_'); - const url = `${OpenAPI.BASE}${path}`; + const url = `${options.baseUrl}${path}`; if (options.query) { return `${url}${getQueryString(options.query)}`; diff --git a/src/templates/core/node/getHeaders.hbs b/src/templates/core/node/getHeaders.hbs index fc6d55164..320938e3e 100644 --- a/src/templates/core/node/getHeaders.hbs +++ b/src/templates/core/node/getHeaders.hbs @@ -1,8 +1,8 @@ async function getHeaders(options: ApiRequestOptions): Promise { - const token = await resolve(options, OpenAPI.TOKEN); - const username = await resolve(options, OpenAPI.USERNAME); - const password = await resolve(options, OpenAPI.PASSWORD); - const defaultHeaders = await resolve(options, OpenAPI.HEADERS); + const token = await resolve(options, options.token); + const username = await resolve(options, options.username); + const password = await resolve(options, options.password); + const defaultHeaders = await resolve(options, options.headers); const headers = new Headers({ Accept: 'application/json', diff --git a/src/templates/core/xhr/getHeaders.hbs b/src/templates/core/xhr/getHeaders.hbs index 3d1a62c7e..88a728c38 100644 --- a/src/templates/core/xhr/getHeaders.hbs +++ b/src/templates/core/xhr/getHeaders.hbs @@ -1,8 +1,8 @@ async function getHeaders(options: ApiRequestOptions): Promise { - const token = await resolve(options, OpenAPI.TOKEN); - const username = await resolve(options, OpenAPI.USERNAME); - const password = await resolve(options, OpenAPI.PASSWORD); - const defaultHeaders = await resolve(options, OpenAPI.HEADERS); + const token = await resolve(options, options.token); + const username = await resolve(options, options.username); + const password = await resolve(options, options.password); + const defaultHeaders = await resolve(options, options.headers); const headers = new Headers({ Accept: 'application/json', diff --git a/src/templates/exportService.hbs b/src/templates/exportService.hbs index c45ed830d..0eb297b41 100644 --- a/src/templates/exportService.hbs +++ b/src/templates/exportService.hbs @@ -5,13 +5,22 @@ import type { {{{this}}} } from '../models/{{{this}}}'; {{/each}} {{/if}} +import { ApiRequestOptions } from '../core/ApiRequestOptions'; import { request as __request } from '../core/request'; -{{#if @root.useVersion}} -import { OpenAPI } from '../core/OpenAPI'; -{{/if}} +import { ApiOptions } from '../core/ApiOptions'; export class {{{name}}} { + private readonly config: ApiOptions; + + /** + * creates a new service + * @param config the configuration to use + */ + public constructor(config: ApiOptions) { + this.config = config; + } + {{#each operations}} /** {{#if deprecated}} @@ -35,8 +44,44 @@ export class {{{name}}} { {{/each}} * @throws ApiError */ - public static async {{{name}}}({{>parameters}}): Promise<{{>result}}> { - const result = await __request({ + public async {{{name}}}({{>parameters}}): Promise<{{>result}}> { + const options = this.{{{name}}}ApiRequestOptions( + {{~#if parameters.length~}} + { + {{#each parameters}} + {{{name}}}: {{{name}}}, + {{/each}} + } + {{/if}} + ); + const result = await __request(options); + return result.body; + } + + /** + {{#if deprecated}} + * @deprecated + {{/if}} + * **used to get the request options without making a http request** + {{#if summary}} + * {{{summary}}} + {{/if}} + {{#if description}} + * {{{description}}} + {{/if}} + {{#unless @root.useOptions}} + {{#if parameters}} + {{#each parameters}} + * @param {{{name}}} {{{description}}} + {{/each}} + {{/if}} + {{/unless}} + * @returns ApiRequestOptions the request options to fulfill a http request + * @throws ApiError + */ + public {{{name}}}ApiRequestOptions({{>parameters}}): ApiRequestOptions { + return { + ...this.config, method: '{{{method}}}', path: `{{{path}}}`, {{#if parametersCookie}} @@ -83,9 +128,8 @@ export class {{{name}}} { {{/each}} }, {{/if}} - }); - return result.body; + }; } {{/each}} -} +} \ No newline at end of file diff --git a/src/templates/index.hbs b/src/templates/index.hbs index e10436ba6..4c1137db4 100644 --- a/src/templates/index.hbs +++ b/src/templates/index.hbs @@ -2,7 +2,7 @@ {{#if @root.exportCore}} export { ApiError } from './core/ApiError'; -export { OpenAPI } from './core/OpenAPI'; +export { ApiOptions, DefaultApiOptions } from './core/ApiOptions'; {{/if}} {{#if @root.exportModels}} {{#if models}} diff --git a/src/utils/registerHandlebarTemplates.ts b/src/utils/registerHandlebarTemplates.ts index 347b2b98b..082f8b4d2 100644 --- a/src/utils/registerHandlebarTemplates.ts +++ b/src/utils/registerHandlebarTemplates.ts @@ -27,7 +27,7 @@ import nodeGetResponseBody from '../templates/core/node/getResponseBody.hbs'; import nodeGetResponseHeader from '../templates/core/node/getResponseHeader.hbs'; import nodeRequest from '../templates/core/node/request.hbs'; import nodeSendRequest from '../templates/core/node/sendRequest.hbs'; -import templateCoreSettings from '../templates/core/OpenAPI.hbs'; +import templateCoreSettings from '../templates/core/ApiOptions.hbs'; import templateCoreRequest from '../templates/core/request.hbs'; import xhrGetHeaders from '../templates/core/xhr/getHeaders.hbs'; import xhrGetRequestBody from '../templates/core/xhr/getRequestBody.hbs'; diff --git a/src/utils/writeClientCore.ts b/src/utils/writeClientCore.ts index c7cac72f8..496b1003b 100644 --- a/src/utils/writeClientCore.ts +++ b/src/utils/writeClientCore.ts @@ -20,7 +20,7 @@ export async function writeClientCore(client: Client, templates: Templates, outp version: client.version, }; - await writeFile(resolve(outputPath, 'OpenAPI.ts'), templates.core.settings(context)); + await writeFile(resolve(outputPath, 'ApiOptions.ts'), templates.core.settings(context)); await writeFile(resolve(outputPath, 'ApiError.ts'), templates.core.apiError({})); await writeFile(resolve(outputPath, 'ApiRequestOptions.ts'), templates.core.apiRequestOptions({})); await writeFile(resolve(outputPath, 'ApiResult.ts'), templates.core.apiResult({})); diff --git a/src/utils/writeClientServices.ts b/src/utils/writeClientServices.ts index 8f82e0ce4..af65b0052 100644 --- a/src/utils/writeClientServices.ts +++ b/src/utils/writeClientServices.ts @@ -6,7 +6,7 @@ import { writeFile } from './fileSystem'; import { format } from './format'; import { Templates } from './registerHandlebarTemplates'; -const VERSION_TEMPLATE_STRING = 'OpenAPI.VERSION'; +const VERSION_TEMPLATE_STRING = 'this.config.version'; /** * Generate Services using the Handlebar template and write to disk. diff --git a/test/custom/request.ts b/test/custom/request.ts index 0c246a6b7..c98f24129 100644 --- a/test/custom/request.ts +++ b/test/custom/request.ts @@ -3,11 +3,10 @@ /* eslint-disable */ import type { ApiRequestOptions } from './ApiRequestOptions'; import type { ApiResult } from './ApiResult'; -import { OpenAPI } from './OpenAPI'; export async function request(options: ApiRequestOptions): Promise { - const url = `${OpenAPI.BASE}${options.path}`; + const url = `${options.baseUrl}${options.path}`; // Do your request...