Skip to content

Commit

Permalink
- Adding wip for Angular client
Browse files Browse the repository at this point in the history
  • Loading branch information
ferdikoomen committed Jan 24, 2022
1 parent 40ef68f commit 975d44e
Show file tree
Hide file tree
Showing 23 changed files with 363 additions and 77 deletions.
2 changes: 1 addition & 1 deletion bin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const params = program
.version(pkg.version)
.requiredOption('-i, --input <value>', 'OpenAPI specification, can be a path, url or string content (required)')
.requiredOption('-o, --output <value>', 'Output directory (required)')
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, axios]', 'fetch')
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, axios, angular]', 'fetch')
.option('--useOptions', 'Use options instead of arguments')
.option('--useUnionTypes', 'Use union types instead of enums')
.option('--exportCore <value>', 'Write core files to disk', true)
Expand Down
23 changes: 14 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,15 @@
"codecov": "codecov --token=66c30c23-8954-4892-bef9-fbaed0a2e42b"
},
"dependencies": {
"@types/node-fetch": "^2.5.12",
"abort-controller": "^3.0.0",
"axios": "^0.25.0",
"camelcase": "^6.3.0",
"commander": "^8.3.0",
"form-data": "^4.0.0",
"handlebars": "^4.7.6",
"json-schema-ref-parser": "^9.0.7",
"node-fetch": "^2.6.6"
"json-schema-ref-parser": "^9.0.7"
},
"devDependencies": {
"@angular/common": "13.1.3",
"@angular/core": "13.1.3",
"@angular/platform-browser": "13.1.3",
"@babel/cli": "7.16.8",
"@babel/core": "7.16.12",
"@babel/preset-env": "7.16.11",
Expand All @@ -80,27 +78,34 @@
"@types/glob": "7.2.0",
"@types/jest": "27.4.0",
"@types/node": "17.0.10",
"@types/node-fetch": "^2.5.12",
"@types/qs": "6.9.7",
"@typescript-eslint/eslint-plugin": "5.10.0",
"@typescript-eslint/parser": "5.10.0",
"@typescript-eslint/eslint-plugin": "5.10.1",
"@typescript-eslint/parser": "5.10.1",
"abort-controller": "^3.0.0",
"axios": "^0.25.0",
"codecov": "3.8.3",
"eslint": "8.7.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "4.0.0",
"eslint-plugin-simple-import-sort": "7.0.0",
"express": "4.17.2",
"form-data": "^4.0.0",
"glob": "7.2.0",
"jest": "27.4.7",
"jest-cli": "27.4.7",
"node-fetch": "^2.6.6",
"prettier": "2.5.1",
"puppeteer": "13.1.1",
"qs": "6.10.3",
"rimraf": "^3.0.2",
"rollup": "2.66.0",
"rollup-plugin-node-externals": "3.1.2",
"rollup-plugin-terser": "7.0.2",
"rxjs": "7.5.2",
"ts-node": "10.4.0",
"tslib": "2.3.1",
"typescript": "4.5.5"
"typescript": "4.5.5",
"zone.js": "0.11.4"
}
}
1 change: 1 addition & 0 deletions src/HttpClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export enum HttpClient {
XHR = 'xhr',
NODE = 'node',
AXIOS = 'axios',
ANGULAR = 'angular',
}
42 changes: 42 additions & 0 deletions src/templates/core/angular/getHeaders.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
async function getHeaders(options: ApiRequestOptions): Promise<HttpHeaders> {
const token = await resolve(options, OpenAPI.TOKEN);
const username = await resolve(options, OpenAPI.USERNAME);
const password = await resolve(options, OpenAPI.PASSWORD);
const additionalHeaders = await resolve(options, OpenAPI.HEADERS);

const defaultHeaders = Object.entries({
Accept: 'application/json',
...additionalHeaders,
...options.headers,
})
.filter(([_, value]) => isDefined(value))
.reduce((headers, [key, value]) => ({
...headers,
[key]: String(value),
}), {} as Record<string, string>);

const headers = new HttpHeaders(defaultHeaders);

if (isStringWithValue(token)) {
headers.append('Authorization', `Bearer ${token}`);
}

if (isStringWithValue(username) && isStringWithValue(password)) {
const credentials = base64(`${username}:${password}`);
headers.append('Authorization', `Basic ${credentials}`);
}

if (options.body) {
if (options.mediaType) {
headers.append('Content-Type', options.mediaType);
} else if (isBlob(options.body)) {
headers.append('Content-Type', options.body.type || 'application/octet-stream');
} else if (isString(options.body)) {
headers.append('Content-Type', 'text/plain');
} else if (!isFormData(options.body)) {
headers.append('Content-Type', 'application/json');
}
}

return headers;
}
12 changes: 12 additions & 0 deletions src/templates/core/angular/getRequestBody.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
if (options.body) {
if (options.mediaType?.includes('/json')) {
return JSON.stringify(options.body)
} else if (isString(options.body) || isBlob(options.body) || isFormData(options.body)) {
return options.body;
} else {
return JSON.stringify(options.body);
}
}
return;
}
18 changes: 18 additions & 0 deletions src/templates/core/angular/getResponseBody.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
async function getResponseBody(response: Response): Promise<any> {
if (response.status !== 204) {
try {
const contentType = response.headers.get('Content-Type');
if (contentType) {
const isJSON = contentType.toLowerCase().startsWith('application/json');
if (isJSON) {
return await response.json();
} else {
return await response.text();
}
}
} catch (error) {
console.error(error);
}
}
return;
}
9 changes: 9 additions & 0 deletions src/templates/core/angular/getResponseHeader.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function getResponseHeader(response: Response, responseHeader?: string): string | undefined {
if (responseHeader) {
const content = response.headers.get(responseHeader);
if (isString(content)) {
return content;
}
}
return;
}
97 changes: 97 additions & 0 deletions src/templates/core/angular/request.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{{>header}}

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

import { ApiError } from './ApiError';
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import { OpenAPI } from './OpenAPI';

{{>functions/isDefined}}


{{>functions/isString}}


{{>functions/isStringWithValue}}


{{>functions/isBlob}}


{{>functions/isFormData}}


{{>functions/base64}}


{{>functions/getQueryString}}


{{>functions/getUrl}}


{{>functions/getFormData}}


{{>functions/resolve}}


{{>angular/getHeaders}}


{{>angular/getRequestBody}}


{{>angular/sendRequest}}


{{>angular/getResponseHeader}}


{{>angular/getResponseBody}}


{{>functions/catchErrors}}


/**
* Request using fetch client
* @param http The Angular HTTP client
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export function request<T>(http: HttpClient, options: ApiRequestOptions): Observable<T> {
return new CancelablePromise<T>(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(options);

if (!onCancel.isCancelled) {
const response = await sendRequest(options, url, formData, body, headers, onCancel);
const responseBody = await getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);

const result: ApiResult = {
url,
ok: response.ok,
status: response.status,
statusText: response.statusText,
body: responseHeader || responseBody,
};

catchErrors(options, result);

resolve(result.body);
}
} catch (error) {
reject(error);
}
});
}
25 changes: 25 additions & 0 deletions src/templates/core/angular/sendRequest.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
async function sendRequest(
options: ApiRequestOptions,
url: string,
formData: FormData | undefined,
body: BodyInit | undefined,
headers: Headers,
onCancel: OnCancel
): Promise<Response> {
const controller = new AbortController();

const request: RequestInit = {
headers,
body: body || formData,
method: options.method,
signal: controller.signal,
};

if (OpenAPI.WITH_CREDENTIALS) {
request.credentials = OpenAPI.CREDENTIALS;
}

onCancel(() => controller.abort());

return await fetch(url, request);
}
2 changes: 1 addition & 1 deletion src/templates/core/axios/request.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import { OpenAPI } from './OpenAPI';
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return new CancelablePromise(async (resolve, reject, onCancel) => {
return new CancelablePromise<T>(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const formData = getFormData(options);
Expand Down
2 changes: 1 addition & 1 deletion src/templates/core/fetch/request.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ import { OpenAPI } from './OpenAPI';
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return new CancelablePromise(async (resolve, reject, onCancel) => {
return new CancelablePromise<T>(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const formData = getFormData(options);
Expand Down
2 changes: 1 addition & 1 deletion src/templates/core/node/request.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import { OpenAPI } from './OpenAPI';
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return new CancelablePromise(async (resolve, reject, onCancel) => {
return new CancelablePromise<T>(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const formData = getFormData(options);
Expand Down
1 change: 1 addition & 0 deletions src/templates/core/request.hbs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{{~#equals @root.httpClient 'fetch'}}{{>fetch/request}}{{/equals~}}
{{~#equals @root.httpClient 'xhr'}}{{>xhr/request}}{{/equals~}}
{{~#equals @root.httpClient 'axios'}}{{>axios/request}}{{/equals~}}
{{~#equals @root.httpClient 'angular'}}{{>angular/request}}{{/equals~}}
{{~#equals @root.httpClient 'node'}}{{>node/request}}{{/equals~}}
2 changes: 1 addition & 1 deletion src/templates/core/xhr/request.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ import { OpenAPI } from './OpenAPI';
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
return new CancelablePromise(async (resolve, reject, onCancel) => {
return new CancelablePromise<T>(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const formData = getFormData(options);
Expand Down
24 changes: 24 additions & 0 deletions src/templates/exportService.hbs
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
{{>header}}

{{#equals @root.httpClient 'angular'}}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
{{/equals}}

{{#if imports}}
{{#each imports}}
import type { {{{this}}} } from '../models/{{{this}}}';
{{/each}}
{{/if}}
{{#notEquals @root.httpClient 'angular'}}
import type { CancelablePromise } from '../core/CancelablePromise';
{{/notEquals}}
import { request as __request } from '../core/request';
{{#if @root.useVersion}}
import { OpenAPI } from '../core/OpenAPI';
{{/if}}

{{#equals @root.httpClient 'angular'}}
@Injectable()
{{/equals}}
export class {{{name}}}{{{@root.postfix}}} {
{{#equals @root.httpClient 'angular'}}
private readonly http: HttpClient;

constructor(http: HttpClient) {
this.http = http;
}
{{/equals}}

{{#each operations}}
/**
Expand All @@ -36,8 +54,14 @@ export class {{{name}}}{{{@root.postfix}}} {
{{/each}}
* @throws ApiError
*/
{{#equals @root.httpClient 'angular'}}
public {{{name}}}({{>parameters}}): Observable<{{>result}}> {
return __request(this.http, {
{{/equals}}
{{#notEquals @root.httpClient 'angular'}}
public static {{{name}}}({{>parameters}}): CancelablePromise<{{>result}}> {
return __request({
{{/notEquals}}
method: '{{{method}}}',
path: `{{{path}}}`,
{{#if parametersCookie}}
Expand Down
1 change: 1 addition & 0 deletions src/templates/partials/base.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{{~#equals @root.httpClient 'fetch'}}Blob{{/equals~}}
{{~#equals @root.httpClient 'xhr'}}Blob{{/equals~}}
{{~#equals @root.httpClient 'axios'}}Blob{{/equals~}}
{{~#equals @root.httpClient 'angular'}}Blob{{/equals~}}
{{~#equals @root.httpClient 'node'}}Blob{{/equals~}}
{{~else~}}
{{{base}}}
Expand Down
Loading

0 comments on commit 975d44e

Please sign in to comment.