i try to generate a typescript-angular sdk based on the openapi spec from loopback4, but swagger-codegen keeps ignoring my query parameter objects.
In the spec below you see the path GET /plans which can have a filter query param.
In the generated class you the the generated method planControllerFind(?:, observe: ...)
which has just ?:
as the first parameter instead of planControllerFind(filter?: FilterClass, observe: ...)
I've tried some different spec structures and also tried different versions from swagger-codegen (3.0.11, 3.0.16, 3.0.18) but nothing seems to work. The Online Version also generates incomplete code.
Can anyone give me a hint ?
the code was generated with:
swagger-codegen generate -i http://localhost:3000/explorer/openapi.json -l typescript-angular -o app/src/app/core/lb4-sdk -c ./swagger-sdk.options.json
where the /swagger-sdk.options.json
-file looks like this:
{
"npmName": "@ilem0n/ng-budget-api",
"npmVersion": "0.0.1",
"snapshot": true,
"ngVersion": "5.0.0"
}
here is my spec which is generated from loopback4:
openapi: 3.0.0
info:
title: ngbm-api - NGBM API v1.0
version: 1.0.0
contact: {}
paths:
/plans:
post:
x-controller-name: PlanController
x-operation-name: create
tags:
- PlanController
responses:
'200':
description: User model instance
content:
application/json:
schema:
$ref: '#/components/schemas/Plan'
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PlanNew'
operationId: PlanController.create
get:
x-controller-name: PlanController
x-operation-name: find
tags:
- PlanController
responses:
'200':
description: Array of User has many Plan
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Plan'
parameters:
- name: filter
in: query
content:
application/json:
schema:
type: object
title: Plan.Filter
properties:
offset:
type: integer
minimum: 0
limit:
type: integer
minimum: 1
example: 100
skip:
type: integer
minimum: 0
order:
type: array
items:
type: string
where:
title: Plan.WhereFilter
type: object
additionalProperties: true
fields:
title: Plan.Fields
type: object
properties:
id:
type: boolean
name:
type: boolean
ownerId:
type: boolean
additionalProperties: false
include:
title: Plan.IncludeFilter
type: array
items:
title: Plan.IncludeFilter.Items
type: object
properties:
relation:
type: string
scope:
properties:
offset:
type: integer
minimum: 0
limit:
type: integer
minimum: 1
example: 100
skip:
type: integer
minimum: 0
order:
type: array
items:
type: string
where:
type: object
additionalProperties: true
fields:
type: object
properties: {}
additionalProperties: true
additionalProperties: false
title: Plan.ScopeFilter
additionalProperties: false
operationId: PlanController.find
/users/login:
post:
x-controller-name: UserController
x-operation-name: login
tags:
- UserController
responses:
'200':
description: Auth & User data
content:
application/json:
schema:
$ref: '#/components/schemas/Auth'
requestBody:
description: The input of login function
required: true
content:
application/json:
schema:
title: Credentials
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
minLength: 8
operationId: UserController.login
/users/me:
get:
x-controller-name: UserController
x-operation-name: getUserData
tags:
- UserController
security:
- name:
- Bearer
responses:
'200':
description: Current user data
content:
application/json:
schema:
title: User
type: object
required:
- id
- name
- email
properties:
id:
type: string
name:
type: string
email:
type: string
operationId: UserController.getUserData
/users:
post:
x-controller-name: UserController
x-operation-name: create
tags:
- UserController
responses:
'200':
description: User model instance
content:
application/json:
schema:
title: User
type: object
required:
- id
- name
- email
properties:
id:
type: string
name:
type: string
email:
type: string
requestBody:
description: The input of register function
required: true
content:
application/json:
schema:
title: NewUser
type: object
required:
- name
- email
- password
properties:
name:
type: string
minLength: 3
email:
type: string
format: email
password:
type: string
minLength: 8
operationId: UserController.create
servers:
- url: /
components:
schemas:
Plan:
title: Plan
description: '(Schema options: { title: ''Plan'', exclude: [ ''ownerId'' ] })'
properties:
id:
type: string
name:
type: string
required:
- name
additionalProperties: false
PlanNew:
title: PlanNew
description: '(Schema options: { title: ''PlanNew'', exclude: [ ''id'', ''ownerId'' ] })'
properties:
name:
type: string
required:
- name
additionalProperties: false
Auth:
title: Auth
properties:
token:
type: string
expiresAt:
type: number
user:
type: object
required:
- token
- expiresAt
- user
additionalProperties: false
from this spec ive got the following class for the planController:
/**
* ngbm-api - NGBM API v1.0
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*//* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent } from '@angular/common/http';
import { CustomHttpUrlEncodingCodec } from '../encoder';
import { Observable } from 'rxjs/Observable';
import { Plan } from '../model/plan';
import { PlanNew } from '../model/planNew';
import { BASE_PATH, COLLECTION_FORMATS } from '../variables';
import { Configuration } from '../configuration';
@Injectable()
export class PlanControllerService {
protected basePath = 'http://localhost:3000/';
public defaultHeaders = new HttpHeaders();
public configuration = new Configuration();
constructor(protected httpClient: HttpClient, @Optional()@Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (basePath) {
this.basePath = basePath;
}
if (configuration) {
this.configuration = configuration;
this.basePath = basePath || configuration.basePath || this.basePath;
}
}
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
/**
*
*
* @param body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public planControllerCreate(body?: PlanNew, observe?: 'body', reportProgress?: boolean): Observable<Plan>;
public planControllerCreate(body?: PlanNew, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Plan>>;
public planControllerCreate(body?: PlanNew, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Plan>>;
public planControllerCreate(body?: PlanNew, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
let headers = this.defaultHeaders;
// to determine the Accept header
let httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set('Content-Type', httpContentTypeSelected);
}
return this.httpClient.request<Plan>('post',`${this.basePath}/plans`,
{
body: body,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
/**
*
*
* @param
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public planControllerFind(?: , observe?: 'body', reportProgress?: boolean): Observable<Array<Plan>>;
public planControllerFind(?: , observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<Array<Plan>>>;
public planControllerFind(?: , observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<Array<Plan>>>;
public planControllerFind(?: , observe: any = 'body', reportProgress: boolean = false ): Observable<any> {
let queryParameters = new HttpParams({encoder: new CustomHttpUrlEncodingCodec()});
if ( !== undefined && !== null) {
queryParameters = queryParameters.set('filter', <any>);
}
let headers = this.defaultHeaders;
// to determine the Accept header
let httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}
// to determine the Content-Type header
const consumes: string[] = [
];
return this.httpClient.request<Array<Plan>>('get',`${this.basePath}/plans`,
{
params: queryParameters,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}
}
content.application-json
, which means the parameter is serialized as a JSON string i.e./plans?filter={"offset":0,"limit":0, ...}
. Is this what you actually need? Complex nested objects should ideally be sent in the POST request body, not in the GET query string. 2) Most likely, Codegen doesn't support parameters withcontent
because they are rarely used. Open an issue at github.com/swagger-api/swagger-codegen/issues. – Helen/plans/filter=%7B%22offset%22%3A0%2C%22limit%22%3A0%7D
. So the consent would be to make a post request for each request which defines some query parameters ? I had a configuration which works well, than had to update some loopback packages the deployment break in this point. Now I want to figure out why it breaks. But im not so deep into openapi to figure this out. – Peter C. Glade