acacode / swagger-typescript-api Goto Github PK
View Code? Open in Web Editor NEWTypeScript API generator via Swagger scheme
License: MIT License
TypeScript API generator via Swagger scheme
License: MIT License
Hi!
Thinks for a great library, we use it quite a lot for generating API types for our frontend, based on the backend spec.
However, I'm having issues with additionalProperties
(using the OpenAPI v3 spec) mapping to empty interfaces.
As an example from our source code, we have the following Typescript interfaces:
export type Primitive = string | number | boolean | null
export interface PrimitiveMap {
[key: string]: Primitive
}
We use tsoa
to generate an OpenAPI v3 spec which looks something like this:
"Primitive": {
"anyOf": [
{
"type": "string"
},
{
"type": "number",
"format": "double"
},
{
"type": "boolean"
},
{
"type": "number",
"enum": [
null
],
"nullable": true
}
]
},
"PrimitiveMap": {
"properties": {},
"type": "object",
"additionalProperties": {
"$ref": "#/components/schemas/Primitive"
}
},
AFAICT, the spec looks right. But when I generate the types with swagger-typescript-api
I get the following results:
export type Primitive = string | number | boolean | "null" | (string & number & boolean & "null");
export interface PrimitiveMap {}
Notice how the PrimitiveMap
is empty.
Instead, I would have expected:
export type Primitive = string | number | boolean | "null" | (string & number & boolean & "null");
export interface PrimitiveMap {
[key: string]: Primitive
}
All help would be much appreciated!
Getting type error in addQueryParams
using typescript 3.9
this.request<any, any>(`/something/${this.addQueryParams(query)}`, "GET", params, null)
Argument of type '{ params?: QueryParams | undefined; } | undefined' is not assignable to parameter of type 'Record<string, string | number | boolean | string[] | number[] | undefined> | undefined'.
Type '{ params?: QueryParams | undefined; }' is not assignable to type 'Record<string, string | number | boolean | string[] | number[] | undefined>'.
Property 'params' is incompatible with index signature.
Type 'QueryParams | undefined' is not assignable to type 'string | number | boolean | string[] | number[] | undefined'.
Type 'QueryParams' is not assignable to type 'string | number | boolean | string[] | number[] | undefined'.
Type 'QueryParams' is missing the following properties from type 'number[]': length, pop, push, concat, and 28 more.
where QueryParams is generated as
export interface QueryParams {
/**
* Page number
*/
page?: number | null;
/**
* Page size
*/
"page-size"?: number | null;
}
openapi: 3.0.1
info:
title: API
description: Documentation
version: "0.1"
paths:
/something/:
get:
operationId: gets
parameters:
- name: params
in: query
required: false
explode: true
schema:
$ref: '#/components/schemas/QueryParams'
components:
schemas:
QueryParams:
type: object
properties:
page:
minimum: 0
type: integer
description: Page number
format: int32
nullable: true
page-size:
minimum: 0
type: integer
description: Page size
format: int32
nullable: true
With explode
set the query url would have ?page=0&page-size=0
Any help would be appreciated.
SyntaxError: An identifier or keyword cannot immediately follow a numeric literal.
SyntaxError: An identifier or keyword cannot immediately follow a numeric literal. (161:4)
159 | NONE = "NONE",
160 | FEED = "FEED",
161 | 2DBARCODE = "2D_BARCODE",
| ^
162 | INTERACTIVE = "INTERACTIVE"
163 | }
164 |
The corresponding schema can be seen here
The error is resulting variable name start with number which is against JS variable naming rules.
I will see if I can fix and raise a PR but if you have a solution already please share
My dev machine use swagger endpoint on https with a self-signed certificate.
If I run swagger-typescript-api I get this error:
(node:14680) UnhandledPromiseRejectionWarning: Error: self signed certificate in certificate chain at TLSSocket.onConnectSecure (_tls_wrap.js:1498:34) at TLSSocket.emit (events.js:315:20) at TLSSocket._finishInit (_tls_wrap.js:940:8) at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:698:12) (Use
node --trace-warnings ...to show where the warning was created) (node:14680) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag
--unhandled-rejections=strict(see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2) (node:14680) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
Would be possibile to add an options to accept also self-signed certiificate?
Tnx
Fabio
Currently, the plugin does not reflect readonly properties. Also, there should be an option to allow export to .d.ts
file
When a swagger model contains additionalProperties: true
I think that the created TypeScript interfaces should deal with this somehow.
Maybe by adding [key: string]?: any,
, at least as a stop-gap.
Hi,
I really liked your library but I have an issue with a React project. Create React App project does not support "const enums" because of Babel. You can look at link for more information: facebook/create-react-app#5681
Could you remove "const" modifier from "enum" at client.mustache?
P.S: I know that in a ideal world I should create an issue at Create React App project but it looks like they will or can not fix it. So I create here.
I have an API that needs to differentiate between properties that are T | null
and T | undefined
. It looks like using nullable
works for basic types but is ignored for $ref
:
schemas:
TestObject:
type: object
properties:
stringMaybeUndefined:
type: string
stringMaybeNullA:
type: string
nullable: true
stringMaybeNullB:
anyOf:
- type: string
nullable: true
otherObjectMaybeUndefined:
$ref: "#/components/schemas/OtherObject"
otherObjectMaybeNullA:
$ref: "#/components/schemas/OtherObject"
nullable: true
otherObjectMaybeNullB:
anyOf:
- $ref: "#/components/schemas/OtherObject"
nullable: true
required:
- stringMaybeNullA
- stringMaybeNullB
- otherObjectMaybeNullA
- otherObjectMaybeNullB
OtherObject:
type: object
Generates:
export interface TestObject {
stringMaybeUndefined?: string;
stringMaybeNullA?: string | null;
stringMaybeNullB?: string;
otherObjectMaybeUndefined?: OtherObject;
otherObjectMaybeNullA?: OtherObject;
otherObjectMaybeNullB?: OtherObject;
}
Note: The OpenAPI 3.1 syntax
oneOf:
- $ref: "#/components/schemas/OtherObject"
- type: 'null'
works, but I'm forced to use OpenAPI 3.0 because of constraints from other tooling.
Can this be achieved somehow?
Edit, relevant resources:
If I interpret these (long) discussions correctly, at least the allOf
wrapping should work?
Currently utility output a lot of warnings about duplicate method naming. I think it should be fixed when custom operation id generator will be improved.
Part of schema:
"ObjectType": {
"type": "object",
"properties": {
"nonNullableField": {
"type": "integer",
"format": "int32"
},
"nullableField": {
"type": "string",
"nullable": true
}
}
}
Starting from version 1.12 enum values like this ERROR_NO_KEY
converted to ERRORNOKEY = "ERROR_NO_KEY"
which is incorrect and ideally should remain the same.
Hi, when running v4 with the following params I am getting an error. Running on node v12.18.3. I can include the swagger definition if needed.
swagger-typescript-api -p "url" -o ./src/api -n file.ts
\node_modules\swagger-typescript-api\src\routes.js:415
tags?.length && * @tags ${tags.join(", ")}
,
^
SyntaxError: Unexpected token '.'
at wrapSafe (internal/modules/cjs/loader.js:1053:16)
at Module._compile (internal/modules/cjs/loader.js:1101:27)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
at Module.load (internal/modules/cjs/loader.js:985:32)
at Function.Module._load (internal/modules/cjs/loader.js:878:14)
at Module.require (internal/modules/cjs/loader.js:1025:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object. (C:\Code\SBIR_TeacherPortal\node_modules\swagger-typescript-api\src\index.js:12:38)
at Module._compile (internal/modules/cjs/loader.js:1137:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)
I have a spring rest endpoint like:
@RestController
@RequestMapping("/util")
public class UtilResource {
@Transactional
@GetMapping
@RequestMapping("/generator")
public void generate(@RequestParam("count") int count) {
It generates below Typescript code but I do not want List at end of method name. Is there way to prevent that?
util = {
/**
* @name generatorList
* @request GET:/util/generator
*/
generatorList: (query?: { count?: number }, params?: RequestParams) =>
this.request<any, any>(`/util/generator${this.addQueryParams(query)}`, "GET", params),
};
An invalid Typescript type is generated in contexts where all of the following criteria are met:
allOf
specificationallOf
contains at least two type specificationsallOf
types contains an array property of enum
values-
)I suspect the issue to be the following code snippet:
swagger-typescript-api/src/typeFormatters.js
Lines 31 to 37 in acc770b
checkAndRenameModelName
will find a hyphen in the described situation, Lodash's startCase
function and whitespace removal is executed on the whole subtype, causing distortions in the output as shown below (undesired casing, missing punctuation and missing spacing). It might be a sufficient fix to just remove the checkAndRenameModelName
there.
openapi: 3.0.1
info:
title: Test
version: test
paths: {}
components:
schemas:
Test:
type: object
allOf:
- type: object
properties:
x:
type: array
items:
type: string
enum:
- A-B
- type: object
properties:
y:
type: string
export type Test = XAB & { y?: string };
Hi,
I am wondering why from this schema:
Manufacturer: {
type: "object",
properties: {
id: {
type: "string",
format: "uuid"
},
created: {
type: "string",
format: "date-time"
},
modified: {
type: "string",
format: "date-time"
},
name: {
type: "string",
nullable: true
},
identificationNumber: {
type: "string",
nullable: true
}
},
additionalProperties: false
},
I am getting this:
export interface Manufacturer {
id?: string;
created?: string;
modified?: string;
name?: string | null;
identificationNumber?: string | null;
}
instead of this:
export interface Manufacturer {
id: string;
created: string;
modified: string;
name: string | null; //or name?: string;
identificationNumber: string | null; //or identificationNumber?: string;
}
Am I doing something wrong?
For example I have:
enum: [resolved, new, in progress]
And I get this error:
☄️ start generating your typescript api
SyntaxError: An enum member name must be followed by a ',', '=', or '}'. (19:6)
17 | resolved = "resolved",
18 | new = "new",
> 19 | in progress = "in progress"
| ^
20 | }
21 |
at t (/project/node_modules/prettier/parser-typescript.js:1:287)
at Object.parse (/project/node_modules/prettier/parser-typescript.js:14:2633274)
at Object.parse (/project/node_modules/prettier/index.js:11370:19)
at coreFormat (/project/node_modules/prettier/index.js:14784:25)
at format (/project/node_modules/prettier/index.js:15019:75)
at formatWithCursor (/project/node_modules/prettier/index.js:15035:12)
at /project/node_modules/prettier/index.js:51620:12
at Object.format (/project/node_modules/prettier/index.js:51640:12)
at /project/node_modules/swagger-typescript-api/src/index.js:89:39 {
This is because it doesn’t add quotes around the enum declaration. That is, instead of outputting:
export enum Enum {
resolved = "resolved",
new = "new",
in progress = "in progress",
}
should be:
export enum Enum {
resolved = "resolved",
new = "new",
"in progress" = "in progress",
}
Is any way to generate swagger.json to JS (instead of TS)?
The latest release update (version 1.8.1
) introduced array types using the typical brackets-suffixed notation (${content}[]
). However, the generator seems to produce faulty type definitions when the array is to contain a union of types or a union of enum values. That problem has not occured with previous versions using the Array<T>
notation. An easy fix respecting the intentions of release 1.8.1
may be to put the content type inside parentheses to which the brackets-suffix can be applied.
Generated code: 1.8.1
generated type to the left, pre-1.8.1
generated type to the right
Hello,
Is there any way how to easily change how enums are generated?
Shema
DayOfWeek: {
enum: [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
],
type: "string"
},
Instead of this
export enum DayOfWeek {
Sunday = "Sunday",
Monday = "Monday",
Tuesday = "Tuesday",
Wednesday = "Wednesday",
Thursday = "Thursday",
Friday = "Friday",
Saturday = "Saturday",
}
I would like to have this
export type DayOfWeek =
| "Sunday"
| "Monday"
| "Tuesday"
| "Wednesday"
| "Thursday"
| "Friday"
| "Saturday";
Thanks in advance
When using this library with my project, that has the tsconfig setting of noUnusedParameters
set to true, I get errors with the generated client at safeParseResponse
This is because neither the E
generic type is used, nor is the captured e
variable in the catch handler (see attached)
I resolve this locally by prefixing both variables with an underscore, but it would be nice not to have to re-apply this every time I regenerate the client.
Looking at the client template it appears the E
generic type is sometimes used, when the config setting generateResponses
is specified (which I'm not currently), but not in all instances, so fix will need to respect that.
But the caught e
variable is never used, so that could simply be removed?
No issue, I just wanted to let you know how awesome this is!
I had 2 issues and I got them quickly solved by adding some additional config options outlined in the ReadMe and now it works perfectly!
Thanks and keep up the great work!
As a developer I'd like to be able to dynamically point the client's baseUrl at a previously unspecified url. This is useful because many CI/CD pipelines dynamically generates urls and it would be useful to dynamically set the url without re-generating the client code.
I could see this done as an environment variable that sets the baseUrl, and some switch in the command to insert the environment variable.
Example:
npx swagger-typescript-api --dynamic-url
public baseUrl: string = process.env.CLIENT_BASE_URL;
My example is Swagger 2, I'm not sure if OpenAPI 3.x specs are affected as well (I only work in Swagger still).
Path Items are able to extend the schema using ^x-
fields, docs: https://swagger.io/specification/v2/#patterned-fields-1
Example spec
"paths": {
"/foo/bar": {
"x-swagger-router-controller": "foo",
"get": { ... }
}
}
Generated Client
export class Api<SecurityDataType = any> extends HttpClient<SecurityDataType> {
example = {
/**
* @name xSwaggerRouterControllerFoo
* @request X SWAGGER ROUTER CONTROLLER:/foo/bar
*/
xSwaggerRouterControllerFoo: (params?: RequestParams) =>
this.request<any, any>(`/foo/bar`, "X SWAGGER ROUTER CONTROLLER", params),
...
Generated Namespace
/**
* @name xSwaggerRouterControllerFoo
* @request X SWAGGER ROUTER CONTROLLER:/foo/bar
*/
export namespace XSwaggerRouterControllerFoo {
export type RequestQuery = {};
export type RequestBody = never;
export type ResponseBody = any;
}
The expected behavior is that these extensions would be ignored when collating the operations.
It might be as simple as replacing this omit
with a pick
and a hard-coded list of verbs.
swagger-typescript-api/src/routes.js
Line 179 in 7a23584
swagger-typescript-api/src/routes.js
Line 177 in 7a23584
private addQueryParams(query: object): string {
const keys = Object.keys(query);
return keys.length ? (
'?' +
keys.reduce((paramsArray, param) => [
...paramsArray,
param + '=' + encodeURIComponent(query[param])
], []).join('&')
) : ''
}
(parameter) param: string
No overload matches this call.
Overload 1 of 3, '(callbackfn: (previousValue: string, currentValue: string, currentIndex: number, array: string[]) => string, initialValue: string): string', gave the following error.
Type 'string[]' is not assignable to type 'string'.
Overload 2 of 3, '(callbackfn: (previousValue: never[], currentValue: string, currentIndex: number, array: string[]) => never[], initialValue: never[]): never[]', gave the following error.
Type 'string[]' is not assignable to type 'never[]'.
Type 'string' is not assignable to type 'never'.ts(2769)
lib.es5.d.ts(1350, 24): The expected type comes from the return type of this signature.
lib.es5.d.ts(1356, 27): The expected type comes from the return type of this signature.
I suggest following code:
private addQueryParams(query: {[key:string]:string|number|boolean}): string {
const keys = Object.keys(query);
return keys.length === 0 ? ''
: '?' + keys.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(query[key])).join('&')
}
Currently this library seems to ignore format
information on data types. Most formats just add some metadata, so they are fine to skip, but format: date-time
actually has semantic meaning that could be understood by a typescript client.
Right now, if we have a model definition like this:
"SomeType": {
"properties": {
"created": {
"type": "string",
"format": "date-time"
}
}
}
it generates this kind of model:
interface SomeType {
created: string;
}
There is no way for the client to know that this string represents a date. It would be really useful if it could generate this model instead:
interface SomeType {
created: Date;
}
I realize that adding custom data transformations is tricky and probably outside the scope of this library. But making only dates work might actually be possible.
Serializing data would be relatively straightforward. JSON serialization would just work. For form serialization there would need to be a special case for Date
instances.
The main challenge for implementation seems to make safeParseResponse work, because type information is not available at run-time. I think the only way to make that work is generate a custom parser per API type. Is that outside the scope of this library too?
I'd be happy to lend a hand if you think this would be a useful addition to the library. I am aware that templates can be customized, so I might also be able to work around this if necessary.
Converting the http response into the return data or an error takes place in
return fetch(requestUrl, requestOptions).then(async (response) => {
const data = await this.safeParseResponse<T, E>(response);
if (!response.ok) throw data;
return data;
});
If this could be placed into a protected function, then its could be sub classed and overridden.
i.e.
return fetch(requestUrl, requestOptions).then(async (response) => {
return await this.handleResponse(response);
});
}
protected async handleResponse<T, E>(response: Response): Promise<HttpResponse<T, E>> {
const data = await this.safeParseResponse<T, E>(response);
if (!response.ok) throw data;
return data;
}
Note safeParseResponse also needs changing to protected, it may also be a good idea to export HttpResponse
Full Template.
export type RequestParams = Omit<RequestInit, "body" | "method"> & {
secure?: boolean;
}
{{#hasQueryRoutes}}
export type RequestQueryParamsType = Record<string | number, any>;
{{/hasQueryRoutes}}
interface ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> {
baseUrl?: string;
baseApiParams?: RequestParams;
securityWorker?: (securityData: SecurityDataType) => RequestParams;
}
{{#generateResponses}}
/** Overrided Promise type. Needs for additional typings of `.catch` callback */
type TPromise<ResolveType, RejectType = any> = Omit<Promise<ResolveType>, "then" | "catch"> & {
then<TResult1 = ResolveType, TResult2 = never>(onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: RejectType) => TResult2 | PromiseLike<TResult2>) | undefined | null): TPromise<TResult1 | TResult2, RejectType>;
catch<TResult = never>(onrejected?: ((reason: RejectType) => TResult | PromiseLike<TResult>) | undefined | null): TPromise<ResolveType | TResult, RejectType>;
}
{{/generateResponses}}
interface HttpResponse<D extends unknown, E extends unknown = unknown> extends Response {
data: D | null;
error: E | null;
}
enum BodyType {
Json,
{{#hasFormDataRoutes}}
FormData,
{{/hasFormDataRoutes}}
}
class HttpClient<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> {
public baseUrl: string = "{{apiConfig.baseUrl}}";
private securityData: SecurityDataType = (null as any);
private securityWorker: null | ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}>["securityWorker"] = null;
private baseApiParams: RequestParams = {
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
}
constructor(apiConfig: ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> = {}) {
Object.assign(this, apiConfig);
}
public setSecurityData = (data: SecurityDataType) => {
this.securityData = data
}
{{#hasQueryRoutes}}
private addQueryParam(query: RequestQueryParamsType, key: string) {
return encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key])
}
protected addQueryParams(rawQuery?: RequestQueryParamsType): string {
const query = rawQuery || {};
const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
return keys.length ? `?${keys.map(key =>
typeof query[key] === "object" && !Array.isArray(query[key]) ?
this.addQueryParams(query[key] as object).substring(1) :
this.addQueryParam(query, key)).join("&")
}` : "";
}
{{/hasQueryRoutes}}
private bodyFormatters: Record<BodyType, (input: any) => any> = {
[BodyType.Json]: JSON.stringify,
{{#hasFormDataRoutes}}
[BodyType.FormData]: (input: any) =>
Object.keys(input).reduce((data, key) => {
data.append(key, input[key]);
return data;
}, new FormData()),
{{/hasFormDataRoutes}}
}
private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams {
return {
...this.baseApiParams,
...params,
...(securityParams || {}),
headers: {
...(this.baseApiParams.headers || {}),
...(params.headers || {}),
...((securityParams && securityParams.headers) || {})
}
}
}
protected safeParseResponse = <T = any, E = any>(response: Response): Promise<HttpResponse<T, E>> => {
const r = response as HttpResponse<T, E>;
r.data = null;
r.error = null;
return response
.json()
.then((data) => {
if (r.ok) {
r.data = data;
} else {
r.error = data;
}
return r;
})
.catch((e) => {
r.error = e;
return r;
});
}
public request = <T = any, E = any>(
path: string,
method: string,
{ secure, ...params }: RequestParams = {},
body?: any,
bodyType?: BodyType,
secureByDefault?: boolean,
): {{#generateResponses}}TPromise<HttpResponse<T, E>>{{/generateResponses}}{{^generateResponses}}Promise<HttpResponse<T>>{{/generateResponses}} => {
const requestUrl = `${this.baseUrl}${path}`;
const secureOptions = (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {};
const requestOptions = {
...this.mergeRequestOptions(params, secureOptions),
method,
body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null,
}
return fetch(requestUrl, requestOptions).then(async (response) => {
return await this.handleResponse(response);
});
}
protected async handleResponse<T, E>(response: Response): Promise<HttpResponse<T, E>> {
const data = await this.safeParseResponse<T, E>(response);
if (!response.ok) throw data;
return data;
}
}
Hello Team, following is my swagger, it generates the types for schema whereas it doesn't generates the types for requestbodies. Have a look into this.
{
"openapi": "3.0.2",
"info": {
"title": "Movie",
"version": "0.0.1",
"description": "Movie API",
"contact": {
"name": "Tech",
"url": "https://production.com",
"email": "[email protected]"
}
},
"servers": [
{
"url": "http://localhost:3000/api",
"description": "local_server"
},
{
"url": "https://production.com/api",
"description": "prod_server"
}
],
"tags": [
{
"name": "movie",
"description": "Everything about shipping rate"
}
],
"paths": {
"/v1/movie/create": {
"post": {
"tags": [
"movie"
],
"description": "Get by its id.",
"operationId": "V1CreateMovieAction",
"requestBody": {
"$ref": "#/components/requestBodies/V1CreateMovieRequestBody"
},
"responses": {
"200": {
"description": "found and returned successfully.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V1CreateMovieResponse"
}
}
}
}
}
}
},
"/v1/movie/update": {
"post": {
"tags": [
"movie"
],
"description": "Get by its id.",
"operationId": "V1UpdateMovieAction",
"requestBody": {
"$ref": "#/components/requestBodies/V1CreateMovieRequestBody"
},
"responses": {
"200": {
"description": "found and returned successfully.",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/V1CreateMovieResponse"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"V1CreateMovieResponse": {
"type": "object",
"properties": {
"msg": {
"type": "string"
}
}
}
},
"requestBodies": {
"V1CreateMovieRequestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "object",
"properties": {
"director": {
"type": "string"
},
"yearReleased": {
"type": "number"
},
"movieName": {
"type": "string"
}
}
}
},
"example": {
"data": {
"director": "Akshat",
"yearReleased": 2020,
"movieName": "MRK"
}
}
}
}
}
}
}
}
}
Hi, Could you change template code so that securityWorker will be async function. I need this so that I can check my JWT token is expired or not and update it if it is expired. I can not do this with current securityWorker.
I suggest you to change current template to below
type ApiConfig<SecurityDataType> = {
baseUrl?: string;
baseApiParams?: RequestParams;
securityWorker?: (securityData: SecurityDataType) => Promise<RequestParams>;
};
public request = async <T = any, E = any>(
path: string,
method: string,
{ secure, ...params }: RequestParams = {},
body?: any,
bodyType?: BodyType,
secureByDefault?: boolean,
): Promise<T> =>{
const securityRequestParams = (secureByDefault || secure) && (await this.securityWorker(this.securityData));
return fetch(`${this.baseUrl}${path}`, {
// @ts-ignore
...this.mergeRequestOptions(params, securityRequestParams),
method,
body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null,
}).then(async (response) => {
const data = await this.safeParseResponse<T, E>(response);
if (!response.ok) throw data;
return data;
});
}
The Swagger 2.0 spec didn't explicitly call out how mixed types are handled, like OpenAPI 3.0 does with oneOf
.
Instead it falls back to JSON Schema Draft 4, which states:
https://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.5.2
5.5.2.1. Valid values
The value of this keyword MUST be either a string or an array. If it
is an array, elements of the array MUST be strings and MUST be
unique.
String values MUST be one of the seven primitive types defined by the
core specification.
However, currently a swagger.json like like the following.
...
"properties": {
"product_id": {
"type": ["integer", "string"]
}
}
...
produces a type like the following
export type SomeRequest = {
product_id: integerString; // Should be `number | string`
}
First, thanks for the awesome library.
Would be really cool if we can extend the default template to support request cancellation...
for example as it's described here: https://react-query.tanstack.com/docs/guides/query-cancellation#using-fetch
what do you think? (in fact it should be easy to change and I can contribute if you give this idea a green light)
p.s I know that there is a possibility to provider a custom template, but would be nice to support it out of the box.
Hi, I tried to understand for a very long time, but I ran out of ideas. After updating to version 3, tests began to fall with this error, in the place where I call the Api class. The project includes a dependency that was generated using swagger-typescript-api, everything was fine on version 2. Any idea why this is happening? Thanks
Test suite failed to run
Jest encountered an unexpected token
This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.
By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".
Here's what you can do:
• If you are trying to use ECMAScript Modules, see https://jestjs.io/docs/en/ecmascript-modules for how to enable it.
• To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
• If you need a custom transformation specify a "transform" option in your config.
• If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.
You'll find more details and examples of these config options in the docs:
https://jestjs.io/docs/en/configuration.html
Details:
/Users/r/project/specifications/lib/index.js:16
export class HttpClient {
^^^^^^
SyntaxError: Unexpected token 'export'
Hi. I'm using swagger-typescript-api v4. 0. 4 as a dev dependency for the project.
The project uses 'prettier' with a specific configuration. The swagger-typescript-api sets the prettier plugin 'prettier-plugin-organize-imports' as dependencies. This plugin does not require any configuration and will work directly after installation. I tried disabling this plugin but couldn't. My team doesn't want to use this add-on for prettier.
Is it possible to move "prettier-plugin-organize-imports" to devDependencies/peerDependencies or delete it?
As an option, I suggest using another plugin with the configuration in prettierrc, for example https://github.com/trivago/prettier-plugin-sort-imports.
Or will anybody suggest a workaround for switch-off 'prettier-plugin-organize-imports'?
Spring automatically generates schema definitions with generic types (see the example for details).
This causes the typescript interfaces to contain underscores in place of "«" symbols when such a schema is used.
Current result:
Page_TemplateResponseDto_
Expected result:
PageTemplateResponseDto
OA version - 2.0
Example schema:
{
"Page«TemplateResponseDto»":{
"type":"object",
"properties":{
"content":{
"type":"array",
"items":{
"$ref":"#/definitions/TemplateResponseDto"
}
},
"empty":{
"type":"boolean"
},
"first":{
"type":"boolean"
},
"last":{
"type":"boolean"
},
"number":{
"type":"integer",
"format":"int32"
},
"numberOfElements":{
"type":"integer",
"format":"int32"
},
"pageable":{
"$ref":"#/definitions/Pageable"
},
"size":{
"type":"integer",
"format":"int32"
},
"sort":{
"$ref":"#/definitions/Sort"
},
"totalElements":{
"type":"integer",
"format":"int64"
},
"totalPages":{
"type":"integer",
"format":"int32"
}
},
"title":"Page«TemplateResponseDto»"
}
}
Hi!
It'd be cool to be able to provide custom templates directory to this tool in order to tweak templates or just leverage the parser to generate custom models or something like that. It's all only about yet another argument e.g. --templates
.
Would it be of your interest if I made a PR with this feature?
Hi, i have schema
EventsList:
properties:
rows:
items:
$ref: '#/definitions/EventRow'
type: array
x-omitempty: false
items:
items:
$ref: '#/definitions/Event'
type: array
x-omitempty: false
total:
format: int64
type: integer
x-omitempty: false
tableFormat:
$ref: '#/definitions/TableFormat'
x-omitempty: false
type: object
and i am getting
export interface EventsList {
rows?: EventRow[];
items?: Event[];
total?: number;
tableFormat?: TableFormat;
}
is it somehow possible to get strick type? we also try x-nullable: false and it works, but x-omitempty no.
Probably it should be void
type ? Now its any
Another small issue I encountered: It is currently not possible to have a /version
endpoint, because of a name collision with the internal version
variable. For example:
---
openapi: 3.0.0
info:
title: SomeAPI
paths:
"/version":
get:
responses:
'200':
description:
content:
application/json:
schema:
type: string
Relevant parts of generated code:
export class Api<SecurityDataType> {
public baseUrl = "";
public title = "SomeAPI";
public version = "";
// and later
version = {
/**
* @name versionList
* @request GET:/version
*/
versionList: (params?: RequestParams) => this.request<string, any>(`/version`, "GET", params, null),
};
Error:
Duplicate identifier 'version'.ts(2300)
According to this information it should be possible to define a nullable type in OpenAPI 3.0.x like this:
schemas:
StringNullable:
type: string
nullable: true
However this generates the following TypeScript:
export type StringNullable = string;
I was hoping it would create:
export type StringNullable = string | null;
The default templates path in index.js
is invalid:
Running:
$ node index.js -p ./tests/schemas/v3.0/additional-properties.yaml -o ./tmp -n myApi.ts
results in:
✨ try to get swagger by path "[...]/swagger-typescript-api/tests/schemas/v3.0/additional-properties.yaml"
✨ try to read templates from directory "[...]/swagger-typescript-api/src/templates"
(node:33407) UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open '[...]/swagger-typescript-api/src/templates/data-contracts.mustache'
I'll submit a PR shortly.
NodeJS is not support fetch
.
Needs to find a better way how to support nodejs usage generated Api module
openapi: '3.0.0'
info:
description: 'Description'
version: 'latest'
title: 'Title'
paths:
'/api':
get:
operationId: getData
responses:
200:
$ref: '#/components/responses/default'
components:
responses:
default:
description: OK
content:
'application/json':
schema:
type: object
properties:
data: { type: string }
Generates the types:
export namespace api {
/**
* @name getData
* @request GET:/api
*/
export namespace GetData {
export type RequestQuery = {};
export type RequestBody = never;
export type ResponseBody = any;
}
}
However if the response type is inlined:
openapi: '3.0.0'
info:
description: 'Description'
version: 'latest'
title: 'Title'
paths:
'/api':
get:
operationId: getData
responses:
200:
description: OK
content:
'application/json':
schema:
type: object
properties:
data: { type: string }
The correct type is output:
export namespace api {
/**
* @name getData
* @request GET:/api
*/
export namespace GetData {
export type RequestQuery = {};
export type RequestBody = never;
export type ResponseBody = { data?: string };
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.