Skip to content

Commit

Permalink
typescript-inversify: improve check for required parameters, support …
Browse files Browse the repository at this point in the history
…multiple media types (#3849)

* [typescript-inversify] Allow falsy parameters

A required parameter to an api method must not be `null` or `undefined`.
It can be any other falsy value, e.g. `""`, `0` or `false` though. This
change makes sure an error is only thrown in the former case and not in
the latter.

* [typescript-inversify] Handle multiple media types

The Accept and Content-Type HTTP headers can contain a list of media
types. Previously all but the first media type in the api definition
were ignored. Now the headers are properly generated.

* [typescript-inversify] Fix http client interface

The api service methods allow the `body` parameter to be optional. The
parameter is then passed to an `IHttpClient`. So it needs to be optional
there as well.
Also fixed the sample implementation `HttpClient`.

Fixes #3618.

* [typescript-inversify] Regenerate Petstore sample

* [typescript-inversify] Use more explicit null check

This does not change the semantic of the generated code, but makes it more explicit.

Co-Authored-By: Esteban Gehring <esteban.gehring@gmail.com>
  • Loading branch information
bodograumann and macjohnny committed Sep 9, 2019
1 parent f2fe4fc commit 9ca4bac
Show file tree
Hide file tree
Showing 10 changed files with 53 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ class HttpClient implements IHttpClient {
return this.performNetworkCall(url, "GET", undefined, headers);
}

post(url: string, body: {}|FormData, headers?: Headers): Observable<HttpResponse> {
post(url: string, body?: {}|FormData, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "POST", this.getJsonBody(body), this.addJsonHeaders(headers));
}

put(url: string, body: {}, headers?: Headers): Observable<HttpResponse> {
put(url: string, body?: {}, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "PUT", this.getJsonBody(body), this.addJsonHeaders(headers));
}

patch(url: string, body: {}, headers?: Headers): Observable<HttpResponse> {
patch(url: string, body?: {}, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "PATCH", this.getJsonBody(body), this.addJsonHeaders(headers));
}

Expand All @@ -36,8 +36,11 @@ class HttpClient implements IHttpClient {
return this.performNetworkCall(url, "DELETE", undefined, headers);
}

private getJsonBody(body: {}|FormData) {
return !(body instanceof FormData) ? JSON.stringify(body) : body;
private getJsonBody(body?: {}|FormData) {
if (body === undefined || body instanceof FormData) {
return body;
}
return JSON.stringify(body);
}

private addJsonHeaders(headers?: Headers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ import { Headers } from "./Headers";

interface IHttpClient {
get(url:string, headers?: Headers):Observable<HttpResponse>
post(url:string, body:{}|FormData, headers?: Headers):Observable<HttpResponse>
put(url:string, body:{}, headers?: Headers):Observable<HttpResponse>
patch(url:string, body:{}, headers?: Headers):Observable<HttpResponse>
post(url:string, body?:{}|FormData, headers?: Headers):Observable<HttpResponse>
put(url:string, body?:{}, headers?: Headers):Observable<HttpResponse>
patch(url:string, body?:{}, headers?: Headers):Observable<HttpResponse>
delete(url:string, headers?: Headers):Observable<HttpResponse>
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class {{classname}} {
public {{nickname}}({{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}observe: any = 'body', headers: Headers = {}): {{#usePromise}}Promise{{/usePromise}}{{^usePromise}}Observable{{/usePromise}}<any> {
{{#allParams}}
{{#required}}
if (!{{paramName}}){
if ({{paramName}} === null || {{paramName}} === undefined){
throw new Error('Required parameter {{paramName}} was null or undefined when calling {{nickname}}.');
}

Expand Down Expand Up @@ -139,7 +139,7 @@ export class {{classname}} {
headers['Accept'] = 'application/json';
{{/produces}}
{{#produces.0}}
headers['Accept'] = '{{{mediaType}}}';
headers['Accept'] = '{{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}';
{{/produces.0}}
{{#bodyParam}}
{{^consumes}}
Expand Down
13 changes: 8 additions & 5 deletions samples/client/petstore/typescript-inversify/HttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class HttpClient implements IHttpClient {
return this.performNetworkCall(url, "GET", undefined, headers);
}

post(url: string, body: {}|FormData, headers?: Headers): Observable<HttpResponse> {
post(url: string, body?: {}|FormData, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "POST", this.getJsonBody(body), this.addJsonHeaders(headers));
}

put(url: string, body: {}, headers?: Headers): Observable<HttpResponse> {
put(url: string, body?: {}, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "PUT", this.getJsonBody(body), this.addJsonHeaders(headers));
}

patch(url: string, body: {}, headers?: Headers): Observable<HttpResponse> {
patch(url: string, body?: {}, headers?: Headers): Observable<HttpResponse> {
return this.performNetworkCall(url, "PATCH", this.getJsonBody(body), this.addJsonHeaders(headers));
}

Expand All @@ -31,8 +31,11 @@ class HttpClient implements IHttpClient {
return this.performNetworkCall(url, "DELETE", undefined, headers);
}

private getJsonBody(body: {}|FormData) {
return !(body instanceof FormData) ? JSON.stringify(body) : body;
private getJsonBody(body?: {}|FormData) {
if (body === undefined || body instanceof FormData) {
return body;
}
return JSON.stringify(body);
}

private addJsonHeaders(headers?: Headers) {
Expand Down
6 changes: 3 additions & 3 deletions samples/client/petstore/typescript-inversify/IHttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { Headers } from "./Headers";

interface IHttpClient {
get(url:string, headers?: Headers):Observable<HttpResponse>
post(url:string, body:{}|FormData, headers?: Headers):Observable<HttpResponse>
put(url:string, body:{}, headers?: Headers):Observable<HttpResponse>
patch(url:string, body:{}, headers?: Headers):Observable<HttpResponse>
post(url:string, body?:{}|FormData, headers?: Headers):Observable<HttpResponse>
put(url:string, body?:{}, headers?: Headers):Observable<HttpResponse>
patch(url:string, body?:{}, headers?: Headers):Observable<HttpResponse>
delete(url:string, headers?: Headers):Observable<HttpResponse>
}

Expand Down
22 changes: 11 additions & 11 deletions samples/client/petstore/typescript-inversify/api/pet.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export class PetService {
public addPet(body: Pet, observe?: 'body', headers?: Headers): Observable<any>;
public addPet(body: Pet, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public addPet(body: Pet, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling addPet.');
}

Expand Down Expand Up @@ -80,7 +80,7 @@ export class PetService {
public deletePet(petId: number, apiKey?: string, observe?: 'body', headers?: Headers): Observable<any>;
public deletePet(petId: number, apiKey?: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public deletePet(petId: number, apiKey?: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!petId){
if (petId === null || petId === undefined){
throw new Error('Required parameter petId was null or undefined when calling deletePet.');
}

Expand Down Expand Up @@ -116,7 +116,7 @@ export class PetService {
public findPetsByStatus(status: Array<'available' | 'pending' | 'sold'>, observe?: 'body', headers?: Headers): Observable<Array<Pet>>;
public findPetsByStatus(status: Array<'available' | 'pending' | 'sold'>, observe?: 'response', headers?: Headers): Observable<HttpResponse<Array<Pet>>>;
public findPetsByStatus(status: Array<'available' | 'pending' | 'sold'>, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!status){
if (status === null || status === undefined){
throw new Error('Required parameter status was null or undefined when calling findPetsByStatus.');
}

Expand All @@ -132,7 +132,7 @@ export class PetService {
: this.APIConfiguration.accessToken;
headers['Authorization'] = 'Bearer ' + accessToken;
}
headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<Array<Pet>>> = this.httpClient.get(`${this.basePath}/pet/findByStatus?${queryParameters.join('&')}`, headers);
if (observe == 'body') {
Expand All @@ -153,7 +153,7 @@ export class PetService {
public findPetsByTags(tags: Array<string>, observe?: 'body', headers?: Headers): Observable<Array<Pet>>;
public findPetsByTags(tags: Array<string>, observe?: 'response', headers?: Headers): Observable<HttpResponse<Array<Pet>>>;
public findPetsByTags(tags: Array<string>, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!tags){
if (tags === null || tags === undefined){
throw new Error('Required parameter tags was null or undefined when calling findPetsByTags.');
}

Expand All @@ -169,7 +169,7 @@ export class PetService {
: this.APIConfiguration.accessToken;
headers['Authorization'] = 'Bearer ' + accessToken;
}
headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<Array<Pet>>> = this.httpClient.get(`${this.basePath}/pet/findByTags?${queryParameters.join('&')}`, headers);
if (observe == 'body') {
Expand All @@ -190,15 +190,15 @@ export class PetService {
public getPetById(petId: number, observe?: 'body', headers?: Headers): Observable<Pet>;
public getPetById(petId: number, observe?: 'response', headers?: Headers): Observable<HttpResponse<Pet>>;
public getPetById(petId: number, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!petId){
if (petId === null || petId === undefined){
throw new Error('Required parameter petId was null or undefined when calling getPetById.');
}

// authentication (api_key) required
if (this.APIConfiguration.apiKeys && this.APIConfiguration.apiKeys["api_key"]) {
headers['api_key'] = this.APIConfiguration.apiKeys["api_key"];
}
headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<Pet>> = this.httpClient.get(`${this.basePath}/pet/${encodeURIComponent(String(petId))}`, headers);
if (observe == 'body') {
Expand All @@ -219,7 +219,7 @@ export class PetService {
public updatePet(body: Pet, observe?: 'body', headers?: Headers): Observable<any>;
public updatePet(body: Pet, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public updatePet(body: Pet, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling updatePet.');
}

Expand Down Expand Up @@ -254,7 +254,7 @@ export class PetService {
public updatePetWithForm(petId: number, name?: string, status?: string, observe?: 'body', headers?: Headers): Observable<any>;
public updatePetWithForm(petId: number, name?: string, status?: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public updatePetWithForm(petId: number, name?: string, status?: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!petId){
if (petId === null || petId === undefined){
throw new Error('Required parameter petId was null or undefined when calling updatePetWithForm.');
}

Expand Down Expand Up @@ -297,7 +297,7 @@ export class PetService {
public uploadFile(petId: number, additionalMetadata?: string, file?: Blob, observe?: 'body', headers?: Headers): Observable<ApiResponse>;
public uploadFile(petId: number, additionalMetadata?: string, file?: Blob, observe?: 'response', headers?: Headers): Observable<HttpResponse<ApiResponse>>;
public uploadFile(petId: number, additionalMetadata?: string, file?: Blob, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!petId){
if (petId === null || petId === undefined){
throw new Error('Required parameter petId was null or undefined when calling uploadFile.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class StoreService {
public deleteOrder(orderId: string, observe?: 'body', headers?: Headers): Observable<any>;
public deleteOrder(orderId: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public deleteOrder(orderId: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!orderId){
if (orderId === null || orderId === undefined){
throw new Error('Required parameter orderId was null or undefined when calling deleteOrder.');
}

Expand Down Expand Up @@ -94,11 +94,11 @@ export class StoreService {
public getOrderById(orderId: number, observe?: 'body', headers?: Headers): Observable<Order>;
public getOrderById(orderId: number, observe?: 'response', headers?: Headers): Observable<HttpResponse<Order>>;
public getOrderById(orderId: number, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!orderId){
if (orderId === null || orderId === undefined){
throw new Error('Required parameter orderId was null or undefined when calling getOrderById.');
}

headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<Order>> = this.httpClient.get(`${this.basePath}/store/order/${encodeURIComponent(String(orderId))}`, headers);
if (observe == 'body') {
Expand All @@ -119,11 +119,11 @@ export class StoreService {
public placeOrder(body: Order, observe?: 'body', headers?: Headers): Observable<Order>;
public placeOrder(body: Order, observe?: 'response', headers?: Headers): Observable<HttpResponse<Order>>;
public placeOrder(body: Order, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling placeOrder.');
}

headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';
headers['Content-Type'] = 'application/json';

const response: Observable<HttpResponse<Order>> = this.httpClient.post(`${this.basePath}/store/order`, body , headers);
Expand Down
22 changes: 11 additions & 11 deletions samples/client/petstore/typescript-inversify/api/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class UserService {
public createUser(body: User, observe?: 'body', headers?: Headers): Observable<any>;
public createUser(body: User, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public createUser(body: User, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling createUser.');
}

Expand All @@ -71,7 +71,7 @@ export class UserService {
public createUsersWithArrayInput(body: Array<User>, observe?: 'body', headers?: Headers): Observable<any>;
public createUsersWithArrayInput(body: Array<User>, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public createUsersWithArrayInput(body: Array<User>, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling createUsersWithArrayInput.');
}

Expand All @@ -97,7 +97,7 @@ export class UserService {
public createUsersWithListInput(body: Array<User>, observe?: 'body', headers?: Headers): Observable<any>;
public createUsersWithListInput(body: Array<User>, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public createUsersWithListInput(body: Array<User>, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling createUsersWithListInput.');
}

Expand All @@ -123,7 +123,7 @@ export class UserService {
public deleteUser(username: string, observe?: 'body', headers?: Headers): Observable<any>;
public deleteUser(username: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public deleteUser(username: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!username){
if (username === null || username === undefined){
throw new Error('Required parameter username was null or undefined when calling deleteUser.');
}

Expand All @@ -148,11 +148,11 @@ export class UserService {
public getUserByName(username: string, observe?: 'body', headers?: Headers): Observable<User>;
public getUserByName(username: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<User>>;
public getUserByName(username: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!username){
if (username === null || username === undefined){
throw new Error('Required parameter username was null or undefined when calling getUserByName.');
}

headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<User>> = this.httpClient.get(`${this.basePath}/user/${encodeURIComponent(String(username))}`, headers);
if (observe == 'body') {
Expand All @@ -174,11 +174,11 @@ export class UserService {
public loginUser(username: string, password: string, observe?: 'body', headers?: Headers): Observable<string>;
public loginUser(username: string, password: string, observe?: 'response', headers?: Headers): Observable<HttpResponse<string>>;
public loginUser(username: string, password: string, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!username){
if (username === null || username === undefined){
throw new Error('Required parameter username was null or undefined when calling loginUser.');
}

if (!password){
if (password === null || password === undefined){
throw new Error('Required parameter password was null or undefined when calling loginUser.');
}

Expand All @@ -190,7 +190,7 @@ export class UserService {
queryParameters.push("password="+encodeURIComponent(String(password)));
}

headers['Accept'] = 'application/xml';
headers['Accept'] = 'application/xml, application/json';

const response: Observable<HttpResponse<string>> = this.httpClient.get(`${this.basePath}/user/login?${queryParameters.join('&')}`, headers);
if (observe == 'body') {
Expand Down Expand Up @@ -232,11 +232,11 @@ export class UserService {
public updateUser(username: string, body: User, observe?: 'body', headers?: Headers): Observable<any>;
public updateUser(username: string, body: User, observe?: 'response', headers?: Headers): Observable<HttpResponse<any>>;
public updateUser(username: string, body: User, observe: any = 'body', headers: Headers = {}): Observable<any> {
if (!username){
if (username === null || username === undefined){
throw new Error('Required parameter username was null or undefined when calling updateUser.');
}

if (!body){
if (body === null || body === undefined){
throw new Error('Required parameter body was null or undefined when calling updateUser.');
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* OpenAPI spec version: 1.0.0
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* OpenAPI spec version: 1.0.0
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
Expand Down

0 comments on commit 9ca4bac

Please sign in to comment.