Skip to content

Commit

Permalink
feat: Support Bearer authorization callback in operations (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
ffflorian committed Aug 7, 2019
1 parent d1b079f commit 44a830e
Show file tree
Hide file tree
Showing 11 changed files with 153 additions and 65 deletions.
10 changes: 10 additions & 0 deletions src/Swaxios.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,16 @@ describe('writeClient', () => {

expect(actual).toBe(expected);
});

it('supports Bearer authorization', async () => {
const inputFile = path.resolve(__dirname, './test/snapshots/7-bearer-auth.json');
await writeClient(inputFile, tempDir, true);

const actual = await fs.readFile(path.join(tempDir, 'rest/api/v1/ExchangeService.ts'), 'utf-8');
const expected = await fs.readFile(path.resolve(__dirname, './test/snapshots/7-bearer-auth.ts.fixture'), 'utf-8');

expect(actual).toBe(expected);
});
});

describe('exportServices', () => {
Expand Down
2 changes: 1 addition & 1 deletion src/generators/MethodGenerator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ describe('MethodGenerator', () => {
expect(methodDefinition.normalizedUrl).toBe('/identity-providers');
expect(methodDefinition.parameterMethod).toBe('postById');
expect(methodDefinition.pathParameters[0]).toEqual({name: 'id', type: 'any'});
expect(methodDefinition.bodyParameters![0]).toEqual({name: 'body', required: false, type: '{ user: string }'});
expect(methodDefinition.bodyParameters[0]).toEqual({name: 'body', required: false, type: '{ user: string }'});
});
});
});
9 changes: 6 additions & 3 deletions src/generators/MethodGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export class MethodGenerator {
readonly bodyParameters: InternalParameter[];
readonly descriptions?: Description[];
readonly formattedUrl: string;
readonly requiresBearerAuthorization: boolean;
readonly method: HttpMethod;
readonly needsDataObj: boolean;
readonly normalizedUrl: string;
Expand All @@ -59,6 +60,7 @@ export class MethodGenerator {
constructor(url: string, method: HttpMethod, operation: OpenAPIV2.OperationObject, spec: OpenAPIV2.Document) {
this.url = url;
this.operation = operation;
this.method = method;
this.normalizedUrl = StringUtil.normalizeUrl(url);
this.formattedUrl = `'${url}'`;
this.spec = spec;
Expand All @@ -83,9 +85,7 @@ export class MethodGenerator {
}

const postFix = parameterMatch ? `By${StringUtil.camelCase(parameterMatch.splice(1), true)}` : 'All';
this.parameterMethod = this.operation.operationId || `${method}${postFix}`;

this.method = method;
this.parameterMethod = this.operation.operationId || `${this.method}${postFix}`;

if (this.includesSuccessResponse(this.responses)) {
this.returnType = this.buildResponseSchema();
Expand All @@ -98,6 +98,9 @@ export class MethodGenerator {
this.method === HttpMethod.POST ||
this.method === HttpMethod.PUT
);

this.requiresBearerAuthorization =
!!this.operation.security && this.operation.security.some(obj => Object.keys(obj).includes('Bearer'));
}

private includesSuccessResponse(
Expand Down
71 changes: 28 additions & 43 deletions src/templates/Resource.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class {{{name}}} {
private readonly apiClient: AxiosInstance;
Expand All @@ -29,6 +29,9 @@ export class {{{name}}} {
{{#each this.bodyParameters}}
{{{this.name}}}{{#isnt this.required true}}?{{/isnt}}: {{{this.type}}},
{{/each}}
{{#if this.requiresBearerAuthorization}}
accessTokenCallback: () => Promise<string>,
{{/if}}
{{#if this.queryParameters.length}}
params?: {
{{#each this.queryParameters}}
Expand All @@ -37,52 +40,34 @@ export class {{{name}}} {
}
{{/if}}
): Promise<{{{this.returnType}}}> => {
const resource = {{{this.formattedUrl}}};
{{#or this.queryParameters.length this.bodyParameters.length}}
{{#if this.needsDataObj}}
const config = {
{{#if this.bodyParameters.length}}
data: {
{{#each this.bodyParameters}}
{{this.name}},
{{/each}}
},
{{/if}}
{{#if this.queryParameters.length}}
params,
{{/if}}
}
{{else}}
{{#eq this.bodyParameters.length 1}}
const data = {{{this.bodyParameters.[0].name}}};
{{/eq}}
{{#gt this.bodyParameters.length}}
const data = {
{{#each this.bodyParameters}}
{{{this.name}}},
{{/each}}
};
{{/gt}}
{{#if this.queryParameters.length}}
const config = {params};
{{/if}}
{{#if this.requiresBearerAuthorization}}
const accessToken = await accessTokenCallback();
{{/if}}
const config: AxiosRequestConfig = {
{{#if this.bodyParameters.length}}
data: {
{{#each this.bodyParameters}}
...{{this.name}},
{{/each}}
},
{{/if}}
{{#if this.requiresBearerAuthorization}}
headers: {
Authorization: `Bearer ${decodeURIComponent(accessToken)}`,
},
{{/if}}
method: '{{{this.method}}}',
{{#if this.queryParameters.length}}
params,
{{/if}}
{{/or}}
url: {{{this.formattedUrl}}},
}
{{#eq this.returnType "void"}}
await this.apiClient.{{{this.method}}}
await this.apiClient.request
{{else}}
const response = await this.apiClient.{{{this.method}}}<{{{this.returnType}}}>
const response = await this.apiClient.request<{{{this.returnType}}}>
{{/eq}}
(
resource,
{{#or this.queryParameters.length this.bodyParameters.length}}
{{#if this.needsDataObj}}
config,
{{else}}
data,
{{/if}}
{{/or}}
);
(config);
{{#isnt this.returnType "void"}}
return response.data;
{{/isnt}}
Expand Down
15 changes: 10 additions & 5 deletions src/test/snapshots/1-query-param-description.ts.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class ArchiveService {
private readonly apiClient: AxiosInstance;
Expand All @@ -21,12 +21,17 @@ export class ArchiveService {
instanceId: string,
body: {archive: {}; conversationId: string}
): Promise<{instanceId: string; name: string}> => {
const resource = `/instance/${instanceId}/archive`;
const data = body;
const response = await this.apiClient.post<{
const config: AxiosRequestConfig = {
data: {
...body,
},
method: 'post',
url: `/instance/${instanceId}/archive`,
};
const response = await this.apiClient.request<{
instanceId: string;
name: string;
}>(resource, data);
}>(config);
return response.data;
};
}
9 changes: 6 additions & 3 deletions src/test/snapshots/3-delete-by-id-number.ts.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class ExchangeService {
private readonly apiClient: AxiosInstance;
Expand All @@ -15,7 +15,10 @@ export class ExchangeService {
}

deleteById = async (id: number): Promise<void> => {
const resource = `/api/v1/exchange/${id}`;
await this.apiClient.delete(resource);
const config: AxiosRequestConfig = {
method: 'delete',
url: `/api/v1/exchange/${id}`,
};
await this.apiClient.request(config);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class ExchangeService {
private readonly apiClient: AxiosInstance;
Expand All @@ -15,8 +15,11 @@ export class ExchangeService {
}

deleteById = async (id: number): Promise<number> => {
const resource = `/api/v1/exchange/${id}`;
const response = await this.apiClient.delete<number>(resource);
const config: AxiosRequestConfig = {
method: 'delete',
url: `/api/v1/exchange/${id}`,
};
const response = await this.apiClient.request<number>(config);
return response.data;
};
}
9 changes: 5 additions & 4 deletions src/test/snapshots/5-query-param-required.ts.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class UserService {
private readonly apiClient: AxiosInstance;
Expand All @@ -19,11 +19,12 @@ export class UserService {
lastname: string;
age?: number;
}): Promise<string> => {
const resource = '/api/user';
const config = {
const config: AxiosRequestConfig = {
method: 'get',
params,
url: '/api/user',
};
const response = await this.apiClient.get<string>(resource, config);
const response = await this.apiClient.request<string>(config);
return response.data;
};
}
9 changes: 6 additions & 3 deletions src/test/snapshots/6-operationId.ts.fixture
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* It should not be modified by hand.
*/

import {AxiosInstance} from 'axios';
import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class ExchangeService {
private readonly apiClient: AxiosInstance;
Expand All @@ -15,7 +15,10 @@ export class ExchangeService {
}

deleteExchange = async (id: number): Promise<void> => {
const resource = `/api/v1/exchange/${id}`;
await this.apiClient.delete(resource);
const config: AxiosRequestConfig = {
method: 'delete',
url: `/api/v1/exchange/${id}`,
};
await this.apiClient.request(config);
};
}
44 changes: 44 additions & 0 deletions src/test/snapshots/7-bearer-auth.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"basePath": "/",
"info": {
"description": "",
"title": "",
"version": ""
},
"paths": {
"/api/v1/exchange/{id}": {
"delete": {
"operationId": "deleteExchange",
"consumes": [
"application/json"
],
"parameters": [
{
"in": "path",
"name": "id",
"required": true,
"type": "number"
}
],
"produces": [
"application/json"
],
"responses": {
"200": {
"description": ""
}
},
"security": [
{
"Bearer": []
}
]
}
}
},
"schemes": [
"http"
],
"swagger": "2.0",
"tags": []
}
31 changes: 31 additions & 0 deletions src/test/snapshots/7-bearer-auth.ts.fixture
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/* tslint:disable */

/**
* This file was automatically generated by "Swaxios".
* It should not be modified by hand.
*/

import {AxiosInstance, AxiosRequestConfig} from 'axios';

export class ExchangeService {
private readonly apiClient: AxiosInstance;

constructor(apiClient: AxiosInstance) {
this.apiClient = apiClient;
}

deleteExchange = async (
id: number,
accessTokenCallback: () => Promise<string>
): Promise<void> => {
const accessToken = await accessTokenCallback();
const config: AxiosRequestConfig = {
headers: {
Authorization: `Bearer ${decodeURIComponent(accessToken)}`,
},
method: 'delete',
url: `/api/v1/exchange/${id}`,
};
await this.apiClient.request(config);
};
}

0 comments on commit 44a830e

Please sign in to comment.