- Woking on httpntlm

This commit is contained in:
Ferdi Koomen 2020-12-16 19:25:27 +01:00
parent 711d835ad5
commit 34d598ac25
16 changed files with 200 additions and 3 deletions

View File

@ -12,7 +12,7 @@ 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]', 'fetch')
.option('-c, --client <value>', 'HTTP client to generate [fetch, xhr, node, httpntlm]', '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)

View File

@ -90,6 +90,7 @@
"express": "4.17.1",
"form-data": "3.0.0",
"glob": "7.1.6",
"httpntlm": "1.7.6",
"jest": "26.6.3",
"jest-cli": "26.6.3",
"node-fetch": "2.6.1",

View File

@ -11,6 +11,7 @@ export enum HttpClient {
FETCH = 'fetch',
XHR = 'xhr',
NODE = 'node',
HTTPNTLM = 'httpntlm',
}
export type Options = {

View File

@ -10,6 +10,7 @@ type Config = {
TOKEN?: string | Resolver<string>;
USERNAME?: string | Resolver<string>;
PASSWORD?: string | Resolver<string>;
DOMAIN?: string | Resolver<string>;
HEADERS?: Headers | Resolver<Headers>;
}
@ -20,5 +21,6 @@ export const OpenAPI: Config = {
TOKEN: undefined,
USERNAME: undefined,
PASSWORD: undefined,
DOMAIN: undefined,
HEADERS: undefined,
};

View File

@ -0,0 +1,31 @@
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
const headers = new Headers({
Accept: 'application/json',
...OpenAPI.HEADERS,
...options.headers,
});
const token = await resolve(OpenAPI.TOKEN);
const username = await resolve(OpenAPI.USERNAME);
const password = await resolve(OpenAPI.PASSWORD);
if (isStringWithValue(token)) {
headers.append('Authorization', `Bearer ${token}`);
}
if (isStringWithValue(username) && isStringWithValue(password)) {
const credentials = Buffer.from(`${username}:${password}`).toString('base64');
headers.append('Authorization', `Basic ${credentials}`);
}
if (options.body) {
if (isBinary(options.body)) {
headers.append('Content-Type', 'application/octet-stream');
} else if (isString(options.body)) {
headers.append('Content-Type', 'text/plain');
} else {
headers.append('Content-Type', 'application/json');
}
}
return headers;
}

View File

@ -0,0 +1,13 @@
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
if (options.formData) {
return getFormData(options.formData);
}
if (options.body) {
if (isString(options.body) || isBinary(options.body)) {
return options.body;
} else {
return JSON.stringify(options.body);
}
}
return undefined;
}

View File

@ -0,0 +1,16 @@
async function getResponseBody(response: Response): Promise<any> {
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 null;
}

View File

@ -0,0 +1,9 @@
function getResponseHeader(response: Response, responseHeader?: string): string | null {
if (responseHeader) {
const content = response.headers.get(responseHeader);
if (isString(content)) {
return content;
}
}
return null;
}

View File

@ -0,0 +1,76 @@
{{>header}}
import FormData from 'form-data';
import fetch, { BodyInit, Headers, RequestInit, Response } from 'node-fetch';
import { types } from 'util';
import { ApiError } from './ApiError';
import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { OpenAPI } from './OpenAPI';
{{>functions/isDefined}}
{{>functions/isString}}
{{>functions/isStringWithValue}}
{{>functions/isBinary}}
{{>functions/getQueryString}}
{{>functions/getUrl}}
{{>functions/getFormData}}
{{>functions/resolve}}
{{>httpntlm/getHeaders}}
{{>httpntlm/getRequestBody}}
{{>httpntlm/sendRequest}}
{{>httpntlm/getResponseHeader}}
{{>httpntlm/getResponseBody}}
{{>functions/catchErrors}}
/**
* Request using node-fetch client
* @param options The request options from the the service
* @result ApiResult
* @throws ApiError
*/
export async function request(options: ApiRequestOptions): Promise<ApiResult> {
const url = getUrl(options);
const response = await sendRequest(options, url);
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);
return result;
}

View File

@ -0,0 +1,8 @@
async function sendRequest(options: ApiRequestOptions, url: string): Promise<Response> {
const request: RequestInit = {
method: options.method,
headers: await getHeaders(options),
body: getRequestBody(options),
};
return await fetch(url, request);
}

View File

@ -1,3 +1,4 @@
{{#equals @root.httpClient 'fetch'}}{{>fetch/request}}{{/equals}}
{{#equals @root.httpClient 'xhr'}}{{>xhr/request}}{{/equals}}
{{#equals @root.httpClient 'node'}}{{>node/request}}{{/equals}}
{{#equals @root.httpClient 'httpntml'}}{{>httpntml/request}}{{/equals}}

View File

@ -26,6 +26,12 @@ import nodeGetResponseBody from '../templates/core/node/getResponseBody.hbs';
import nodeGetResponseHeader from '../templates/core/node/getResponseHeader.hbs';
import nodeRequest from '../templates/core/node/request.hbs';
import nodeSendRequest from '../templates/core/node/sendRequest.hbs';
import httpntlmGetHeaders from '../templates/core/httpntlm/getHeaders.hbs';
import httpntlmGetRequestBody from '../templates/core/httpntlm/getRequestBody.hbs';
import httpntlmGetResponseBody from '../templates/core/httpntlm/getResponseBody.hbs';
import httpntlmGetResponseHeader from '../templates/core/httpntlm/getResponseHeader.hbs';
import httpntlmRequest from '../templates/core/httpntlm/request.hbs';
import httpntlmSendRequest from '../templates/core/httpntlm/sendRequest.hbs';
import templateCoreSettings from '../templates/core/OpenAPI.hbs';
import templateCoreRequest from '../templates/core/request.hbs';
import xhrGetHeaders from '../templates/core/xhr/getHeaders.hbs';
@ -173,5 +179,13 @@ export function registerHandlebarTemplates(): Templates {
Handlebars.registerPartial('node/sendRequest', Handlebars.template(nodeSendRequest));
Handlebars.registerPartial('node/request', Handlebars.template(nodeRequest));
// Specific files for the node client implementation
Handlebars.registerPartial('httpntlm/getHeaders', Handlebars.template(httpntlmGetHeaders));
Handlebars.registerPartial('httpntlm/getRequestBody', Handlebars.template(httpntlmGetRequestBody));
Handlebars.registerPartial('httpntlm/getResponseBody', Handlebars.template(httpntlmGetResponseBody));
Handlebars.registerPartial('httpntlm/getResponseHeader', Handlebars.template(httpntlmGetResponseHeader));
Handlebars.registerPartial('httpntlm/sendRequest', Handlebars.template(httpntlmSendRequest));
Handlebars.registerPartial('httpntlm/request', Handlebars.template(httpntlmRequest));
return templates;
}

View File

@ -67,6 +67,7 @@ type Config = {
TOKEN?: string | Resolver<string>;
USERNAME?: string | Resolver<string>;
PASSWORD?: string | Resolver<string>;
DOMAIN?: string | Resolver<string>;
HEADERS?: Headers | Resolver<Headers>;
}
@ -77,6 +78,7 @@ export const OpenAPI: Config = {
TOKEN: undefined,
USERNAME: undefined,
PASSWORD: undefined,
DOMAIN: undefined,
HEADERS: undefined,
};"
`;
@ -284,6 +286,7 @@ export async function request(options: ApiRequestOptions): Promise<ApiResult> {
return result;
}
"
`;
@ -2310,6 +2313,7 @@ type Config = {
TOKEN?: string | Resolver<string>;
USERNAME?: string | Resolver<string>;
PASSWORD?: string | Resolver<string>;
DOMAIN?: string | Resolver<string>;
HEADERS?: Headers | Resolver<Headers>;
}
@ -2320,6 +2324,7 @@ export const OpenAPI: Config = {
TOKEN: undefined,
USERNAME: undefined,
PASSWORD: undefined,
DOMAIN: undefined,
HEADERS: undefined,
};"
`;
@ -2527,6 +2532,7 @@ export async function request(options: ApiRequestOptions): Promise<ApiResult> {
return result;
}
"
`;

View File

@ -6,7 +6,7 @@ async function generateV2() {
await OpenAPI.generate({
input: './test/spec/v2.json',
output: './test/generated/v2/',
httpClient: OpenAPI.HttpClient.FETCH,
httpClient: OpenAPI.HttpClient.HTTPNTLM,
useOptions: false,
useUnionTypes: false,
exportCore: true,
@ -20,7 +20,7 @@ async function generateV3() {
await OpenAPI.generate({
input: './test/spec/v3.json',
output: './test/generated/v3/',
httpClient: OpenAPI.HttpClient.FETCH,
httpClient: OpenAPI.HttpClient.HTTPNTLM,
useOptions: false,
useUnionTypes: false,
exportCore: true,

1
types/index.d.ts vendored
View File

@ -2,6 +2,7 @@ export declare enum HttpClient {
FETCH = 'fetch',
XHR = 'xhr',
NODE = 'node',
HTTPNTLM = 'httpntlm',
}
export type Options = {

View File

@ -3164,6 +3164,19 @@ http-signature@~1.2.0:
jsprim "^1.2.2"
sshpk "^1.7.0"
httpntlm@1.7.6:
version "1.7.6"
resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.7.6.tgz#6991e8352836007d67101b83db8ed0f915f906d0"
integrity sha1-aZHoNSg2AH1nEBuD247Q+RX5BtA=
dependencies:
httpreq ">=0.4.22"
underscore "~1.7.0"
httpreq@>=0.4.22:
version "0.4.24"
resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.4.24.tgz#4335ffd82cd969668a39465c929ac61d6393627f"
integrity sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=
https-proxy-agent@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-4.0.0.tgz#702b71fb5520a132a66de1f67541d9e62154d82b"
@ -5679,6 +5692,11 @@ unbzip2-stream@^1.3.3:
buffer "^5.2.1"
through "^2.3.8"
underscore@~1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
integrity sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"