Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/generators/typescript-angular.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|supportsES6|Generate code that conforms to ES6.| |false|
|taggedUnions|Use discriminators to create tagged unions instead of extending interfaces.| |false|
|tsVersion|The version of typescript compatible with Angular (see ngVersion option).| |null|
|useHttpResource|Use httpResource to call GET endpoints| |false|
|useSingleRequestParameter|Setting this property to true will generate functions with a single argument containing all API endpoint parameters instead of one argument per parameter.| |false|
|useSquareBracketsInArrayNames|Setting this property to true will add brackets to array attribute names, e.g. my_values[].| |false|
|withInterfaces|Setting this property to true will generate interfaces next to the default class implementations.| |false|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ public boolean getHasVendorExtensions() {
return nonEmpty(vendorExtensions);
}

/**
* Check if th httpMethod is a GET
*
* @return true if httpMethod is a GET, false otherwise
*/
public boolean isGet() {
return "GET".equalsIgnoreCase(httpMethod);
}

/**
* Check if act as Restful index method
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

import java.io.File;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

Expand Down Expand Up @@ -83,6 +84,7 @@ public static enum PROVIDED_IN_LEVEL {none, root, any, platform}
public static final String RXJS_VERSION = "rxjsVersion";
public static final String NGPACKAGR_VERSION = "ngPackagrVersion";
public static final String ZONEJS_VERSION = "zonejsVersion";
public static final String USE_HTTP_RESOURCE = "useHttpResource";

protected String ngVersion = "20.0.0";
@Getter @Setter
Expand All @@ -96,6 +98,7 @@ public static enum PROVIDED_IN_LEVEL {none, root, any, platform}
@Getter protected Boolean stringEnums = false;
protected QUERY_PARAM_OBJECT_FORMAT_TYPE queryParamObjectFormat = QUERY_PARAM_OBJECT_FORMAT_TYPE.dot;
protected PROVIDED_IN_LEVEL providedIn = PROVIDED_IN_LEVEL.root;
@Setter(AccessLevel.PRIVATE) private boolean useHttpResource = false;

private boolean taggedUnions = false;

Expand Down Expand Up @@ -155,6 +158,7 @@ public TypeScriptAngularClientCodegen() {
this.cliOptions.add(new CliOption(RXJS_VERSION, "The version of RxJS compatible with Angular (see ngVersion option)."));
this.cliOptions.add(new CliOption(NGPACKAGR_VERSION, "The version of ng-packagr compatible with Angular (see ngVersion option)."));
this.cliOptions.add(new CliOption(ZONEJS_VERSION, "The version of zone.js compatible with Angular (see ngVersion option)."));
this.cliOptions.add(CliOption.newBoolean(USE_HTTP_RESOURCE, "Use httpResource to call GET endpoints").defaultValue(String.valueOf(this.useHttpResource)));
}

@Override
Expand Down Expand Up @@ -310,6 +314,11 @@ public void processOpts() {
additionalProperties.put("isQueryParamObjectFormatJson", getQueryParamObjectFormatJson());
additionalProperties.put("isQueryParamObjectFormatKey", getQueryParamObjectFormatKey());

if (additionalProperties.containsKey(USE_HTTP_RESOURCE)) {
this.setUseHttpResource(convertPropertyToBoolean(USE_HTTP_RESOURCE));
}
writePropertyBack(USE_HTTP_RESOURCE, getUseHttpResource());

}

@Data
Expand Down Expand Up @@ -434,7 +443,12 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap operations, L

// Prep a string buffer where we're going to set up our new version of the string.
StringBuilder pathBuffer = new StringBuilder();
ParameterExpander paramExpander = new ParameterExpander(op, this::toParamName);
// If useHttpResource=true, means that we use signals and the variable is available under the name `this.toParamName(n) + "Value"`
Function<String, String> paramName =
isUseHttpResource(op)
? n -> this.toParamName(n) + "Value"
: this::toParamName;
ParameterExpander paramExpander = new ParameterExpander(op, paramName);
int insideCurly = 0;

// Iterate through existing string, one character at a time.
Expand Down Expand Up @@ -626,6 +640,10 @@ private String getApiFilenameFromClassname(String classname) {
return toApiFilename(name);
}

private boolean getUseHttpResource() {
return useHttpResource;
}

@Override
public String toModelName(String name) {
name = addSuffix(name, modelSuffix);
Expand Down Expand Up @@ -766,4 +784,8 @@ public void setProvidedIn(String level) {
private boolean getIsProvidedInNone() {
return PROVIDED_IN_LEVEL.none.equals(providedIn);
}

private boolean isUseHttpResource(CodegenOperation operation) {
return useHttpResource && operation.isGet();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{{>licenseInfo}}
/* tslint:disable:no-unused-variable member-ordering */

import { Inject, Injectable, Optional } from '@angular/core';
import { Inject, Injectable, Optional{{#useHttpResource}}, Signal{{/useHttpResource}} } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams,
HttpResponse, HttpEvent{{#httpContextInOptions}}, HttpContext {{/httpContextInOptions}}
HttpResponse, HttpEvent{{#httpContextInOptions}}, HttpContext {{/httpContextInOptions}}{{#useHttpResource}}, httpResource, HttpResourceFn, HttpResourceRef{{/useHttpResource}}
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { OpenApiHttpParams, QueryParamStyle } from '../query.params';
Expand Down Expand Up @@ -67,263 +67,19 @@ export class {{classname}} extends BaseService {
}

{{#operation}}
/**
{{#summary}}
* {{.}}
{{/summary}}
{{#notes}}
* {{.}}
{{/notes}}
* @endpoint {{httpMethod}} {{{vendorExtensions.x-path-from-spec}}}
{{^useSingleRequestParameter}}
{{#allParams}}
* @param {{paramName}} {{description}}
{{/allParams}}
{{/useSingleRequestParameter}}
{{#useSingleRequestParameter}}
{{#allParams.0}}
* @param requestParameters
{{/allParams.0}}
{{/useSingleRequestParameter}}
* @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.
* @param options additional options
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
*/
public {{nickname}}({{^useSingleRequestParameter}}{{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}{{/useSingleRequestParameter}}{{#useSingleRequestParameter}}{{#allParams.0}}requestParameters{{^hasRequiredParams}}?{{/hasRequiredParams}}: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}RequestParams, {{/allParams.0}}{{/useSingleRequestParameter}}observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: {{#produces}}'{{{mediaType}}}'{{^-last}} | {{/-last}}{{/produces}}{{^produces}}undefined{{/produces}},{{#httpContextInOptions}} context?: HttpContext{{/httpContextInOptions}}{{#httpTransferCacheInOptions}}, transferCache?: boolean{{/httpTransferCacheInOptions}}}): Observable<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>;
public {{nickname}}({{^useSingleRequestParameter}}{{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}{{/useSingleRequestParameter}}{{#useSingleRequestParameter}}{{#allParams.0}}requestParameters{{^hasRequiredParams}}?{{/hasRequiredParams}}: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}RequestParams, {{/allParams.0}}{{/useSingleRequestParameter}}observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: {{#produces}}'{{{mediaType}}}'{{^-last}} | {{/-last}}{{/produces}}{{^produces}}undefined{{/produces}},{{#httpContextInOptions}} context?: HttpContext{{/httpContextInOptions}}{{#httpTransferCacheInOptions}}, transferCache?: boolean{{/httpTransferCacheInOptions}}}): Observable<HttpResponse<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>>;
public {{nickname}}({{^useSingleRequestParameter}}{{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}{{/useSingleRequestParameter}}{{#useSingleRequestParameter}}{{#allParams.0}}requestParameters{{^hasRequiredParams}}?{{/hasRequiredParams}}: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}RequestParams, {{/allParams.0}}{{/useSingleRequestParameter}}observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: {{#produces}}'{{{mediaType}}}'{{^-last}} | {{/-last}}{{/produces}}{{^produces}}undefined{{/produces}},{{#httpContextInOptions}} context?: HttpContext{{/httpContextInOptions}}{{#httpTransferCacheInOptions}}, transferCache?: boolean{{/httpTransferCacheInOptions}}}): Observable<HttpEvent<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>>;
public {{nickname}}({{^useSingleRequestParameter}}{{#allParams}}{{paramName}}{{^required}}?{{/required}}: {{{dataType}}}, {{/allParams}}{{/useSingleRequestParameter}}{{#useSingleRequestParameter}}{{#allParams.0}}requestParameters{{^hasRequiredParams}}?{{/hasRequiredParams}}: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}RequestParams, {{/allParams.0}}{{/useSingleRequestParameter}}observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: {{#produces}}'{{{mediaType}}}'{{^-last}} | {{/-last}}{{/produces}}{{^produces}}undefined{{/produces}},{{#httpContextInOptions}} context?: HttpContext{{/httpContextInOptions}}{{#httpTransferCacheInOptions}}, transferCache?: boolean{{/httpTransferCacheInOptions}}}): Observable<any> {
{{#allParams}}
{{#useSingleRequestParameter}}
const {{paramName}} = requestParameters{{^hasRequiredVars}}?{{/hasRequiredVars}}.{{paramName}};
{{/useSingleRequestParameter}}
{{#required}}
if ({{paramName}} === null || {{paramName}} === undefined) {
throw new Error('Required parameter {{paramName}} was null or undefined when calling {{nickname}}.');
}
{{/required}}
{{/allParams}}

{{#hasQueryParamsOrAuth}}
let localVarQueryParameters = new OpenApiHttpParams(this.encoder);
{{#queryParams}}

localVarQueryParameters = this.addToHttpParams(
localVarQueryParameters,
'{{baseName}}',
<any>{{paramName}},
{{#isQueryParamObjectFormatJson}}
QueryParamStyle.Json,
{{/isQueryParamObjectFormatJson}}
{{^isQueryParamObjectFormatJson}}
{{^style}}
{{#queryIsJsonMimeType}}
QueryParamStyle.Json,
{{/queryIsJsonMimeType}}
{{^queryIsJsonMimeType}}
QueryParamStyle.Form,
{{/queryIsJsonMimeType}}
{{/style}}
{{#style}}
{{#isDeepObject}}
QueryParamStyle.DeepObject,
{{/isDeepObject}}
{{#isFormStyle}}
QueryParamStyle.Form,
{{/isFormStyle}}
{{#isSpaceDelimited}}
QueryParamStyle.SpaceDelimited,
{{/isSpaceDelimited}}
{{#isPipeDelimited}}
QueryParamStyle.PipeDelimited,
{{/isPipeDelimited}}
{{#queryIsJsonMimeType}}
QueryParamStyle.Json,
{{/queryIsJsonMimeType}}
{{/style}}
{{/isQueryParamObjectFormatJson}}
{{isExplode}},
);

{{/queryParams}}

{{/hasQueryParamsOrAuth}}
let localVarHeaders = this.defaultHeaders;
{{#headerParams}}
{{#isArray}}
if ({{paramName}}) {
localVarHeaders = localVarHeaders.set('{{baseName}}', [...{{paramName}}].join(COLLECTION_FORMATS['{{collectionFormat}}']));
}
{{/isArray}}
{{^isArray}}
if ({{paramName}} !== undefined && {{paramName}} !== null) {
localVarHeaders = localVarHeaders.set('{{baseName}}', String({{paramName}}));
}
{{/isArray}}
{{/headerParams}}

{{#authMethods}}
// authentication ({{name}}) required
{{#isApiKey}}
{{#isKeyInHeader}}
localVarHeaders = this.configuration.addCredentialToHeaders('{{name}}', '{{keyParamName}}', localVarHeaders);
{{/isKeyInHeader}}
{{#isKeyInQuery}}
localVarQueryParameters = this.configuration.addCredentialToQuery('{{name}}', '{{keyParamName}}', localVarQueryParameters);
{{/isKeyInQuery}}
{{/isApiKey}}
{{#isBasic}}
{{#isBasicBasic}}
localVarHeaders = this.configuration.addCredentialToHeaders('{{name}}', 'Authorization', localVarHeaders, 'Basic ');
{{/isBasicBasic}}
{{#isBasicBearer}}
localVarHeaders = this.configuration.addCredentialToHeaders('{{name}}', 'Authorization', localVarHeaders, 'Bearer ');
{{/isBasicBearer}}
{{/isBasic}}
{{#isOAuth}}
localVarHeaders = this.configuration.addCredentialToHeaders('{{name}}', 'Authorization', localVarHeaders, 'Bearer ');
{{/isOAuth}}

{{/authMethods}}
const localVarHttpHeaderAcceptSelected: string | undefined = options?.httpHeaderAccept ?? this.configuration.selectHeaderAccept([
{{#produces}}
'{{{mediaType}}}'{{^-last}},{{/-last}}
{{/produces}}
]);
if (localVarHttpHeaderAcceptSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Accept', localVarHttpHeaderAcceptSelected);
}

{{#httpContextInOptions}}
const localVarHttpContext: HttpContext = options?.context ?? new HttpContext();
{{/httpContextInOptions}}
{{#httpTransferCacheInOptions}}

const localVarTransferCache: boolean = options?.transferCache ?? true;
{{/httpTransferCacheInOptions}}

{{#bodyParam}}
{{- duplicated below, don't forget to change}}
// to determine the Content-Type header
const consumes: string[] = [
{{#consumes}}
'{{{mediaType}}}'{{^-last}},{{/-last}}
{{/consumes}}
];
{{/bodyParam}}
{{#hasFormParams}}
{{^bodyParam}}
// to determine the Content-Type header
const consumes: string[] = [
{{#consumes}}
'{{{mediaType}}}'{{^-last}},{{/-last}}
{{/consumes}}
];
{{/bodyParam}}
{{/hasFormParams}}
{{#bodyParam}}
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected !== undefined) {
localVarHeaders = localVarHeaders.set('Content-Type', httpContentTypeSelected);
}
{{/bodyParam}}

{{#hasFormParams}}
const canConsumeForm = this.canConsumeForm(consumes);

let localVarFormParams: { append(param: string, value: any): any; };
let localVarUseForm = false;
let localVarConvertFormParamsToString = false;
{{#formParams}}
{{#isFile}}
// use FormData to transmit files using content-type "multipart/form-data"
// see https://stackoverflow.com/questions/4007969/application-x-www-form-urlencoded-or-multipart-form-data
localVarUseForm = canConsumeForm;
{{/isFile}}
{{/formParams}}
if (localVarUseForm) {
localVarFormParams = new FormData();
} else {
localVarFormParams = new HttpParams({encoder: this.encoder});
}

{{#formParams}}
{{#isArray}}
if ({{paramName}}) {
{{#isCollectionFormatMulti}}
{{paramName}}.forEach((element) => {
localVarFormParams = localVarFormParams.append('{{baseName}}{{#useSquareBracketsInArrayNames}}[]{{/useSquareBracketsInArrayNames}}', <any>element) as any || localVarFormParams;
})
{{/isCollectionFormatMulti}}
{{^isCollectionFormatMulti}}
if (localVarUseForm) {
{{paramName}}.forEach((element) => {
localVarFormParams = localVarFormParams.append('{{baseName}}{{#useSquareBracketsInArrayNames}}[]{{/useSquareBracketsInArrayNames}}', <any>element) as any || localVarFormParams;
})
} else {
localVarFormParams = localVarFormParams.append('{{baseName}}{{#useSquareBracketsInArrayNames}}[]{{/useSquareBracketsInArrayNames}}', [...{{paramName}}].join(COLLECTION_FORMATS['{{collectionFormat}}'])) as any || localVarFormParams;
}
{{/isCollectionFormatMulti}}
}
{{/isArray}}
{{^isArray}}
if ({{paramName}} !== undefined) {
localVarFormParams = localVarFormParams.append('{{baseName}}', {{^isModel}}<any>{{paramName}}{{/isModel}}{{#isModel}}localVarUseForm ? new Blob([JSON.stringify({{paramName}})], {type: 'application/json'}) : <any>{{paramName}}{{/isModel}}) as any || localVarFormParams;
}
{{/isArray}}
{{/formParams}}

{{/hasFormParams}}
{{^isResponseFile}}
let responseType_: 'text' | 'json' | 'blob' = 'json';
if (localVarHttpHeaderAcceptSelected) {
if (localVarHttpHeaderAcceptSelected.startsWith('text')) {
responseType_ = 'text';
} else if (this.configuration.isJsonMime(localVarHttpHeaderAcceptSelected)) {
responseType_ = 'json';
} else {
responseType_ = 'blob';
}
}

{{/isResponseFile}}
let localVarPath = `{{{path}}}`;
const { basePath, withCredentials } = this.configuration;
return this.httpClient.request{{^isResponseFile}}<{{#returnType}}{{{returnType}}}{{#isResponseTypeFile}}|undefined{{/isResponseTypeFile}}{{/returnType}}{{^returnType}}any{{/returnType}}>{{/isResponseFile}}('{{httpMethod}}', `${basePath}${localVarPath}`,
{
{{#httpContextInOptions}}
context: localVarHttpContext,
{{/httpContextInOptions}}
{{#bodyParam}}
body: {{paramName}},
{{/bodyParam}}
{{^bodyParam}}
{{#hasFormParams}}
body: localVarConvertFormParamsToString ? localVarFormParams.toString() : localVarFormParams,
{{/hasFormParams}}
{{/bodyParam}}
{{#hasQueryParamsOrAuth}}
params: localVarQueryParameters.toHttpParams(),
{{/hasQueryParamsOrAuth}}
{{#isResponseFile}}
responseType: "blob",
{{/isResponseFile}}
{{^isResponseFile}}
responseType: <any>responseType_,
{{/isResponseFile}}
...(withCredentials ? { withCredentials } : {}),
headers: localVarHeaders,
observe: observe,
{{#httpTransferCacheInOptions}}
...(localVarTransferCache !== undefined ? { transferCache: localVarTransferCache } : {}),
{{/httpTransferCacheInOptions}}
reportProgress: reportProgress
}
);
}
{{#useHttpResource}}
{{#isGet}}
{{> operationHttpResource }}
{{/isGet}}
{{/useHttpResource}}
{{^useHttpResource}}
{{> operationObservable }}
{{/useHttpResource}}
{{#useHttpResource}}
{{^isGet}}
{{> operationObservable }}
{{/isGet}}
{{/useHttpResource}}

{{/operation}}}
{{/operations}}
Loading
Loading