flowup / api-client-generator Goto Github PK
View Code? Open in Web Editor NEWAngular REST API client generator from Swagger YAML or JSON file with camel case settigs
License: MIT License
Angular REST API client generator from Swagger YAML or JSON file with camel case settigs
License: MIT License
export enum PickUpTime {
pUT_ANYTIME = "PUT_ANYTIME",
pUT_MORNING = "PUT_MORNING",
pUT_AFTERNOON = "PUT_AFTERNOON",
}
export enum PickUpTime {
PUT_ANYTIME = "PUT_ANYTIME",
PUT_MORNING = "PUT_MORNING",
PUT_AFTERNOON = "PUT_AFTERNOON",
}
The generator should create the output directory structure if it does not already exist. This would possibly:
mkdir
s if used in an automatic pipeline.The generator should be able to automatically commit its output if asked.
api-client-generator
, API Client Generator
, ...) and a unique, possibly ficticious, email ([email protected]
, [email protected]
). This way it will be distinguishable which changes in the repo were generated and which were made manually by a human contributor.--commit
or -C
flag is provided to the generator andThe nodegit library will be used for Git operations. Git operations should be executed using Git's CLI in child processes. This is to reduce unnecessary dependencies and avoid problems with installing nodegit
on some systems.
Description / Key should be used as property name when generating enum from this yaml definition
enum:
- 1 #Pending
- 2 #InProgress
- 3 #Complete
description: |
- 1 Pending
- 2 InProgress
- 3 Complete
In private sendRequest()
method:
throw is deprecated: In favor of throwError creation function: import { throwError } from 'rxjs';
It would be cool if the API client could generate also embedded models with tag allOf
, because now is ignoring this field.
example:
definitions:
model:
type: "object"
properties:
id:
type: "string"
created:
type: "integer"
updated:
type: "integer"
deleted:
type: "integer"
customer:
type: "object"
allOf:
- $ref: "#/definitions/model"
properties:
name:
type: "string"
address:
type: "string"
generated types sometimes have duplicate word roots
examples:
DiscussionDiscussion
DeliveryDeliveryAddress
ShipmentShipment
some of the method names are generated with the name like
gET_somethingList
should be full camelcase without the underscored prefix
Hi,
I'm having some issues with my generated code. On build I get a bunch of errors like:
.../api-client-service.ts(379,59): error TS2345: Argument of type 'HttpOptions' is not assignable to parameter of type '{ headers?: HttpHeaders | { [header: string]: string | string[]; }; observe?: "body"; params?: Ht...'.
Types of property 'responseType' are incompatible.
Type '"text" | "arraybuffer" | "blob" | "json"' is not assignable to type '"json"'.
Type '"text"' is not assignable to type '"json"'.
This seem to me like it's probably a versioning issue, e.g. the typescript or angular versions are wrong. I'm using Angular 4.x.x with typescript 2.4.0. I tried angular 5.x.x and TS 2.6.x and has the same issues. Maybe the code you generate targets an older angular version?
Additionally HttpObserve
is not exported in /common/http
. To get the generated code to build at all I've edited the HttpOptions interface as follows:
interface HttpOptions {
headers?: HttpHeaders,
params?: HttpParams,
reportProgress?: boolean,
withCredentials?: boolean,
}
Any ideas?
The following type definitions create the same file and the 2nd one overwrites the first:
"ItemList": {
"description": "List of items",
"required": [
"data"
],
"type": "object",
"properties": {
"data": {
"description": "List of controllers in the system (this can be empty)",
"type": "array",
"items": {
"$ref": "#/definitions/Data"
}
},
}
"ItemModelList": {
"description": "List of Item models",
"required": [
"data"
],
"type": "object",
"properties": {
"data": {
"description": "The list of available ItemModels and their configurations",
"type": "array",
"items": {
"$ref": "#/definitions/DataModel"
}
},
}
}
The problem is in 'helper.ts', line 80:
export function fileName(name: string = '', type: 'model' | 'enum' = 'model'): string {
return `${dashCase(name.replace(/model|enum/i, ''))}.${type}`;
}
The 'model' part of the definition name is removed by the replace function and therefore:
ItemModelList becomes ItemList, the same name as the other existing type ItemList and the original model file is overwritten.
If I create API call post
with empty body EmptyProtobuf
it should place in call {}
as a body instead of creating EmptyProtonufModel
and passing it as a parameter in the function.
when you generate an interface and there are same interfaces used in it, it adds the same number of imports as is the number of interfaces in the interface.
typescript ->
import { MyAwesomeModel } from './my-awesome-model.model'
import { MyAwesomeModel } from './my-awesome-model.model'
import { MyAwesomeModel } from './my-awesome-model.model'
export interface MySecondAwesomeModel {
item1: MyAwesomeModel;
item2: MyAwesomeModel;
item3: MyAwesomeModel;
}
swagger ->
mySecondAwesome:
type: "object"
properties:
item1:
$ref: "#/definitions/myAwesome"
item2:
$ref: "#/definitions/myAwesome"
item3:
$ref: "#/definitions/myAwesome"
if generated interface contains itself in a recursive way, there is an unnecessary import
import {
Discussion
} from '..';
export interface Discussion {
authorName: string;
comments: Discussion[];
date: string;
}
This will allow adding more options into each request. These options will be then merged by the angular http implementation together with the default options provided by the generator.
Sample implementation:
class APIService {
readUsers(arguments ..., options): Observable<User[]> {
return http.get('/users', options)
}
}
The specification can be found here https://angular.io/guide/http#configuring-other-parts-of-the-request
Generate angular module with exported API client and forRoot
method to initialize data and provide parameters.
It looks like ngx-module-export.mustache
does not exist in the released version?
/usr/bin/ngx-swag-client -> /usr/lib/node_modules/@flowup/ngx-swagger-client-generator/dist/main.js
+ @flowup/[email protected]
added 26 packages in 6.849s
Error encored during generating { Error: ENOENT: no such file or directory, open '/usr/lib/node_modules/@flowup/ngx-swagger-client-generator/dist/../templates/ngx-module-export.mustache'
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/usr/lib/node_modules/@flowup/ngx-swagger-client-generator/dist/../templates/ngx-module-export.mustache' }
Generator should be capable of generating enums
generate question marks for optional parameters in client service methods
interface property data
should be generated properly
interface Table {
data: Cell[][], // currently will generate `any[]`
header: string[],
}
swagger 3.0
Body and form parameters are replaced with requestBody
When field's name starts with a number it should be quoted
Eg:
interface Sample {
name: string;
'42wololo': string;
}
Instead of (current wrong behavior):
interface Sample {
name: string;
42wololo: string;
}
So the situation is you have a page which contains a bunch of components that might be executing API requests at any time. You then have an event that means you need to just kill everything and take the user somewhere else (e.g. their token expired and you just want to take them back to a login page).
So the current way to do this is to have a ngDestroy
on each component that handles the cancellation of the request either by directly unsubscribing or managing a local takeUntil.
But I think it would be possible to implement a generic solution to this since takeUntil
is implemented before subscribe so the generated sendRequest
method could just attach a takeUntil
to all observables allowing api requests to be globally cancelled via a single event emitter.
Or something like - if an emitter is injected then it adds the takeUntil otherwise it just does the normal thing.
What do you think?
apiClientService
forRoot
providerHello,
Just wondering if it's intended that the swagger property:
"consumes": [
"application/json"
]
is meant to be ignored when generated the API client? I assumed a header would of been generated & applied to API services which have this property? Right now we are adding it to the NGModule as a universal header, but some API Client calls don't use application/json.
Is this intended behaviour or a bug?
Thanks =).
Is the swagger file missing to regenerate the example code (example dir in project)? Additionally it seems like this target is not functional in the package.json:
"gen": "ts-node ./src/main.ts",
I guess it should be ...main.ts -s the-missing-swagger-file.json -o example
.
Types like File
or Blob
are native and shouldn't be imported
method parameters that are enums but not referenced or listed in parameters schema are not generated properly. The enum type is used instead of enum itself.
In this example swagger we can see the enum properties but parameter orderBy
is generated as a string (which is non-breaking but incorrect)
It would be awesome if the API client could generate constructor functions which would automatically fill null fields.
E.g:
interface User {
name: string;
email: string;
}
and the response from the API would be:
{
"email": "[email protected]"
}
the client would automatically migrate this model into:
{
"name": "",
"email": "[email protected]"
}
method params and headers are not using options initialized from client class httpOptions
With the latest released version it seems like there is a discrepancy between how arg properties and placeholders are formatted e.g.
createCustomerInvite(
args: {
customerId: string,
body: models.V2CreateCustomerInviteRequest,
},
options?: HttpOptions
): Observable<models.V2Invite> {
const path = `/api/v2/customers/${args.customer_id}/invites`;
options = {...this.options, ...options};
return this.sendRequest<models.V2Invite>('POST', path, options, JSON.stringify(args.body));
}
customerId
becomes customer_id
in the path.
the swagger definition:
"/api/v2/customers/{customer_id}/invites": {
"post": {
"description": "Create an invite for a new customer user.",
"tags": [
"invite",
"admin"
],
"summary": "Create an invite for a customer",
"operationId": "CreateCustomerInvite",
"parameters": [
{
"type": "string",
"name": "customer_id",
"in": "path",
"required": true
},
{
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/v2CreateCustomerInviteRequest"
}
}
],
"responses": {
"200": {
"schema": {
"$ref": "#/definitions/v2Invite"
}
}
}
}
},
The generator should have an option from each api function to pass on an option whether to return the entire response for one use case and/or to return the expected response data.
Currently the response body is what we're getting/observing.
@vmasek @gelidus
IMO the default value returned should be simplistic as to return the response body alone for most of the use cases.
Expected code snapshot when observing the entire response in
private sendRequest
function
private sendRequest<T>(method: string, uri: string, headers: HttpHeaders, params: HttpParams, body: any): Observable<HttpResponse<T>> { if (method === 'get') { return this.http.get<T>(this.domain + uri, { headers: headers.set('Accept', 'application/json'), params: params, observe: 'response' }); } }
if query param is an array, it should append
all it items to http params
Write info about compatible (and currently supported versions) of Angular in the readme
if the method is sending multipart form request, use the form parameter as a body
Parameters that will be included in URL query are currently not generated for method nor included in request query
when using dash case naming (for example in the file name of an interface), ones with all-caps abbreviations like ID, are generated like foo-i-d-bar
instead of foo-id-bar
Hi flowup,
In my swagger file I have a type, which contains the letters 'any' in it. Your pattern matches this type against BASIC_TS_TYPE_REGEX. Here is the word: Tanulmany
See below my fix for this.
Regards, adamzoltan
old
const BASIC_TS_TYPE_REGEX = /^string|number|integer|boolean|null|undefined|any|Object|Date|File|Blob$/;
new
const BASIC_TS_TYPE_REGEX = /\b(string|number|integer|boolean|null|undefined|any|Object|Date|File|Blob)\b/;
Steps:
After installing api-client-generator ran api-client-generator -s ./api.yaml -o ./apidocs
.
Assumptions:
YAML is valid.
No errors during installation.
Angular CLI: 6.0.7
Node: 10.2.1
OS: darwin x64
Angular: 6.0.3
Stack trace shown:
Error encored during generating TypeError: type.toLocaleLowerCase is not a function
at Object.toTypescriptType (/usr/local/lib/node_modules/api-client-generator/dist/helper.js:46:21)
at /usr/local/lib/node_modules/api-client-generator/dist/parser.js:109:39
at Array.map ()
at parseInterfaceProperties (/usr/local/lib/node_modules/api-client-generator/dist/parser.js:106:39)
at defineInterface (/usr/local/lib/node_modules/api-client-generator/dist/parser.js:161:22)
at defineEnumOrInterface (/usr/local/lib/node_modules/api-client-generator/dist/parser.js:75:11)
at /usr/local/lib/node_modules/api-client-generator/dist/parser.js:62:16
at Array.map ()
at parseDefinitions (/usr/local/lib/node_modules/api-client-generator/dist/parser.js:60:10)
at createMustacheViewModel (/usr/local/lib/node_modules/api-client-generator/dist/parser.js:18:22)
Any input is more than welcomed.
Cheers.
here is an example swagger parameter definition:
{
"type": "array",
"items": {
"type": "string"
},
"name": "filters",
"in": "query"
}
and here is what gets generated for that parameter
listThings(filters: string[], options?: HttpOptions): Observable<models.V2RuleList> {
const path = `/api/v2/things`;
options = {...this.options, ...options};
if (filters) {
options.params = options.params.set('filters', String(filters));
}
return this.sendRequest<models.V2ThingList>('GET', path, options);
}
The filters array ends up being joined with commas.
What should happen:
The generated code for the param should look more like this:
if (filters) {
filters.forEach(v => {
options.params = options.params.append('filters', v);
});
}
This is unfortunately arguable since apparently there is not a clear standard. However multiple params with the same name is the most and reliable approach AFAIK so it should probably be used.
The functionality could be hidden behind a flag for backwards compatibility i.e. it uses set
by default but append
if --append-array-params
is supplied during generation.
HttpOptions reportProgress & withCredentials are not being set on service init.
This happens when we try to pass withCredentials
& reportProgress
from the root module.
Like so below
APIClientModule.forRoot({
domain: 'http://localhost:10507',
httpOptions: {
headers,
withCredentials: true
}
})
],```
If you have an enum in a separate file it generates correctly but importing it somewhere will cause misnaming it should generate xxxEnum
but it generates xxxModel
and even file path is wrong.
Properties with additionalProperties
should be generated as the keymap
Example
INPUT:
myInterface:
type: "object"
properties:
myName:
type: "string"
myId:
type: "string"
myMap:
type: "object"
additionalProperties:
$ref: "#/definitions/someOtherInterface"
OUTPUT:
export interface MyInterface {
myName: string;
myId: string;
myMap: {[key: string]: SomeOtherInterface};
}
Running
$ ng build --prod
while the module is injected to the app.
We get the following error
ERROR in app/app.module.ts(14,21): Error during template compile of 'AppModule' Function calls are not supported in decorators but 'HttpHeaders' was called.
This might be due to the fact that simple assignments are only allowed during module declarations.
and we're trying to pass new HttpHeaders(...header String/objects)
into the module declaration.
Possible Solution:
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.