- Decoupled OpenAPI object from request files

This commit is contained in:
Ferdi Koomen 2022-01-25 11:02:49 +01:00
parent d7479aef16
commit cd24337650
38 changed files with 123 additions and 116 deletions

View File

@ -5,7 +5,7 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
type Headers = Record<string, string>;
type Config = {
export type OpenAPIConfig = {
BASE: string;
VERSION: string;
WITH_CREDENTIALS: boolean;
@ -17,7 +17,7 @@ type Config = {
ENCODE_PATH?: (path: string) => string;
};
export const OpenAPI: Config = {
export const OpenAPI: OpenAPIConfig = {
BASE: '{{{server}}}',
VERSION: '{{{version}}}',
WITH_CREDENTIALS: false,

View File

@ -1,8 +1,8 @@
async function getHeaders(options: ApiRequestOptions, formData?: FormData): Promise<Record<string, string>> {
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 getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions, formData?: FormData): Promise<Record<string, string>> => {
const token = await resolve(options, config.TOKEN);
const username = await resolve(options, config.USERNAME);
const password = await resolve(options, config.PASSWORD);
const additionalHeaders = await resolve(options, config.HEADERS);
const formHeaders = typeof formData?.getHeaders === 'function' && formData?.getHeaders() || {}
const headers = Object.entries({
@ -27,4 +27,4 @@ async function getHeaders(options: ApiRequestOptions, formData?: FormData): Prom
}
return headers;
}
};

View File

@ -1,6 +1,6 @@
function getRequestBody(options: ApiRequestOptions): any {
const getRequestBody = (options: ApiRequestOptions): any => {
if (options.body) {
return options.body;
}
return;
}
};

View File

@ -1,6 +1,6 @@
function getResponseBody(response: AxiosResponse<any>): any {
const getResponseBody = (response: AxiosResponse<any>): any => {
if (response.status !== 204) {
return response.data;
}
return;
}
};

View File

@ -1,4 +1,4 @@
function getResponseHeader(response: AxiosResponse<any>, responseHeader?: string): string | undefined {
const getResponseHeader = (response: AxiosResponse<any>, responseHeader?: string): string | undefined => {
if (responseHeader) {
const content = response.headers[responseHeader];
if (isString(content)) {
@ -6,4 +6,4 @@ function getResponseHeader(response: AxiosResponse<any>, responseHeader?: string
}
}
return;
}
};

View File

@ -8,7 +8,7 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import { OpenAPI } from './OpenAPI';
import { OpenAPIConfig } from './OpenAPI';
{{>functions/isDefined}}
@ -60,20 +60,21 @@ import { OpenAPI } from './OpenAPI';
/**
* Request using axios client
* @param config The OpenAPI configuration object
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(options, formData);
const headers = await getHeaders(config, options, formData);
if (!onCancel.isCancelled) {
const response = await sendRequest(options, url, formData, body, headers, onCancel);
const response = await sendRequest(config, options, url, formData, body, headers, onCancel);
const responseBody = getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);
@ -93,5 +94,5 @@ export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
reject(error);
}
});
}
};

View File

@ -1,11 +1,12 @@
async function sendRequest(
const sendRequest = async (
config: OpenAPIConfig,
options: ApiRequestOptions,
url: string,
formData: FormData | undefined,
body: any,
headers: Record<string, string>,
onCancel: OnCancel
): Promise<AxiosResponse<any>> {
): Promise<AxiosResponse<any>> => {
const source = axios.CancelToken.source();
const config: AxiosRequestConfig = {
@ -13,7 +14,7 @@ async function sendRequest(
headers,
data: body || formData,
method: options.method,
withCredentials: OpenAPI.WITH_CREDENTIALS,
withCredentials: config.WITH_CREDENTIALS,
cancelToken: source.token,
};
@ -28,4 +29,4 @@ async function sendRequest(
}
throw error;
}
}
};

View File

@ -1,8 +1,8 @@
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
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 getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise<Headers> => {
const token = await resolve(options, config.TOKEN);
const username = await resolve(options, config.USERNAME);
const password = await resolve(options, config.PASSWORD);
const additionalHeaders = await resolve(options, config.HEADERS);
const defaultHeaders = Object.entries({
Accept: 'application/json',
@ -39,4 +39,4 @@ async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
}
return headers;
}
};

View File

@ -1,4 +1,4 @@
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
const getRequestBody = (options: ApiRequestOptions): BodyInit | undefined => {
if (options.body) {
if (options.mediaType?.includes('/json')) {
return JSON.stringify(options.body)
@ -9,4 +9,4 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
}
}
return;
}
};

View File

@ -1,4 +1,4 @@
async function getResponseBody(response: Response): Promise<any> {
const getResponseBody = async (response: Response): Promise<any> => {
if (response.status !== 204) {
try {
const contentType = response.headers.get('Content-Type');
@ -15,4 +15,4 @@ async function getResponseBody(response: Response): Promise<any> {
}
}
return;
}
};

View File

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

View File

@ -5,7 +5,7 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import { OpenAPI } from './OpenAPI';
import { OpenAPIConfig } from './OpenAPI';
{{>functions/isDefined}}
@ -57,20 +57,21 @@ import { OpenAPI } from './OpenAPI';
/**
* Request using fetch client
* @param config The OpenAPI configuration object
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(options);
const headers = await getHeaders(config, options);
if (!onCancel.isCancelled) {
const response = await sendRequest(options, url, formData, body, headers, onCancel);
const response = await sendRequest(config, options, url, formData, body, headers, onCancel);
const responseBody = await getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);
@ -90,4 +91,4 @@ export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
reject(error);
}
});
}
};

View File

@ -1,11 +1,12 @@
async function sendRequest(
export const sendRequest = async (
config: OpenAPIConfig,
options: ApiRequestOptions,
url: string,
formData: FormData | undefined,
body: BodyInit | undefined,
headers: Headers,
onCancel: OnCancel
): Promise<Response> {
): Promise<Response> => {
const controller = new AbortController();
const request: RequestInit = {
@ -15,11 +16,11 @@ async function sendRequest(
signal: controller.signal,
};
if (OpenAPI.WITH_CREDENTIALS) {
request.credentials = OpenAPI.CREDENTIALS;
if (config.WITH_CREDENTIALS) {
request.credentials = config.CREDENTIALS;
}
onCancel(() => controller.abort());
return await fetch(url, request);
}
};

View File

@ -1,8 +1,8 @@
function base64(str: string): string {
const base64 = (str: string): string => {
try {
return btoa(str);
} catch (err) {
// @ts-ignore
return Buffer.from(str).toString('base64');
}
}
};

View File

@ -1,4 +1,4 @@
function catchErrors(options: ApiRequestOptions, result: ApiResult): void {
const catchErrors = (options: ApiRequestOptions, result: ApiResult): void => {
const errors: Record<number, string> = {
400: 'Bad Request',
401: 'Unauthorized',
@ -18,4 +18,4 @@ function catchErrors(options: ApiRequestOptions, result: ApiResult): void {
if (!result.ok) {
throw new ApiError(result, 'Generic Error');
}
}
};

View File

@ -1,4 +1,4 @@
function getFormData(options: ApiRequestOptions): FormData | undefined {
const getFormData = (options: ApiRequestOptions): FormData | undefined => {
if (options.formData) {
const formData = new FormData();
@ -23,4 +23,4 @@ function getFormData(options: ApiRequestOptions): FormData | undefined {
return formData;
}
return;
}
};

View File

@ -1,4 +1,4 @@
function getQueryString(params: Record<string, any>): string {
const getQueryString = (params: Record<string, any>): string => {
const searchParams = new URLSearchParams();
const process = (key: string, value: any) => {
@ -27,4 +27,4 @@ function getQueryString(params: Record<string, any>): string {
}
return '';
}
};

View File

@ -1,9 +1,9 @@
function getUrl(options: ApiRequestOptions): string {
const path = OpenAPI.ENCODE_PATH ? OpenAPI.ENCODE_PATH(options.path) : options.path;
const url = `${OpenAPI.BASE}${path}`;
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
const path = config.ENCODE_PATH ? config.ENCODE_PATH(options.path) : options.path;
const url = `${config.BASE}${path}`;
if (options.query) {
return `${url}${getQueryString(options.query)}`;
}
return url;
}
};

View File

@ -1,4 +1,4 @@
function isBlob(value: any): value is Blob {
const isBlob = (value: any): value is Blob => {
return (
typeof value === 'object' &&
typeof value.type === 'string' &&
@ -9,4 +9,4 @@ function isBlob(value: any): value is Blob {
/^(Blob|File)$/.test(value.constructor.name) &&
/^(Blob|File)$/.test(value[Symbol.toStringTag])
);
}
};

View File

@ -1,3 +1,3 @@
function isDefined<T>(value: T | null | undefined): value is Exclude<T, null | undefined> {
const isDefined = <T>(value: T | null | undefined): value is Exclude<T, null | undefined> => {
return value !== undefined && value !== null;
}
};

View File

@ -1,3 +1,3 @@
function isFormData(value: any): value is FormData {
const isFormData = (value: any): value is FormData => {
return value instanceof FormData;
}
};

View File

@ -1,3 +1,3 @@
function isString(value: any): value is string {
const isString = (value: any): value is string => {
return typeof value === 'string';
}
};

View File

@ -1,3 +1,3 @@
function isStringWithValue(value: any): value is string {
const isStringWithValue = (value: any): value is string => {
return isString(value) && value !== '';
}
};

View File

@ -1,3 +1,3 @@
function isSuccess(status: number): boolean {
const isSuccess = (status: number): boolean => {
return status >= 200 && status < 300;
}
};

View File

@ -1,8 +1,8 @@
type Resolver<T> = (options: ApiRequestOptions) => Promise<T>;
async function resolve<T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> {
const resolve = async <T>(options: ApiRequestOptions, resolver?: T | Resolver<T>): Promise<T | undefined> => {
if (typeof resolver === 'function') {
return (resolver as Resolver<T>)(options);
}
return resolver;
}
};

View File

@ -1,8 +1,8 @@
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
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 getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise<Headers> => {
const token = await resolve(options, config.TOKEN);
const username = await resolve(options, config.USERNAME);
const password = await resolve(options, config.PASSWORD);
const additionalHeaders = await resolve(options, config.HEADERS);
const defaultHeaders = Object.entries({
Accept: 'application/json',
@ -38,4 +38,4 @@ async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
}
}
return headers;
}
};

View File

@ -1,4 +1,4 @@
function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
const getRequestBody = (options: ApiRequestOptions): BodyInit | undefined => {
if (options.body) {
if (options.mediaType?.includes('/json')) {
return JSON.stringify(options.body)
@ -9,4 +9,4 @@ function getRequestBody(options: ApiRequestOptions): BodyInit | undefined {
}
}
return;
}
};

View File

@ -1,4 +1,4 @@
async function getResponseBody(response: Response): Promise<any> {
const getResponseBody = async (response: Response): Promise<any> => {
if (response.status !== 204) {
try {
const contentType = response.headers.get('Content-Type');
@ -15,4 +15,4 @@ async function getResponseBody(response: Response): Promise<any> {
}
}
return;
}
};

View File

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

View File

@ -9,7 +9,7 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import { OpenAPI } from './OpenAPI';
import { OpenAPIConfig } from './OpenAPI';
{{>functions/isDefined}}
@ -61,17 +61,18 @@ import { OpenAPI } from './OpenAPI';
/**
* Request using node-fetch client
* @param config The OpenAPI configuration object
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(options);
const headers = await getHeaders(config, options);
if (!onCancel.isCancelled) {
const response = await sendRequest(options, url, formData, body, headers, onCancel);
@ -94,4 +95,4 @@ export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
reject(error);
}
});
}
};

View File

@ -1,11 +1,11 @@
async function sendRequest(
export const sendRequest = async (
options: ApiRequestOptions,
url: string,
formData: FormData | undefined,
body: BodyInit | undefined,
headers: Headers,
onCancel: OnCancel
): Promise<Response> {
): Promise<Response> => {
const controller = new AbortController();
const request: RequestInit = {
@ -18,4 +18,4 @@ async function sendRequest(
onCancel(() => controller.abort());
return await fetch(url, request);
}
};

View File

@ -1,8 +1,8 @@
async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
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 getHeaders = async (config: OpenAPIConfig, options: ApiRequestOptions): Promise<Headers> => {
const token = await resolve(options, config.TOKEN);
const username = await resolve(options, config.USERNAME);
const password = await resolve(options, config.PASSWORD);
const additionalHeaders = await resolve(options, config.HEADERS);
const defaultHeaders = Object.entries({
Accept: 'application/json',
@ -38,4 +38,4 @@ async function getHeaders(options: ApiRequestOptions): Promise<Headers> {
}
}
return headers;
}
};

View File

@ -1,4 +1,4 @@
function getRequestBody(options: ApiRequestOptions): any {
const getRequestBody = (options: ApiRequestOptions): any => {
if (options.body) {
if (options.mediaType?.includes('/json')) {
return JSON.stringify(options.body)
@ -10,4 +10,4 @@ function getRequestBody(options: ApiRequestOptions): any {
}
return;
}
};

View File

@ -1,4 +1,4 @@
function getResponseBody(xhr: XMLHttpRequest): any {
const getResponseBody = (xhr: XMLHttpRequest): any => {
if (xhr.status !== 204) {
try {
const contentType = xhr.getResponseHeader('Content-Type');
@ -15,4 +15,4 @@ function getResponseBody(xhr: XMLHttpRequest): any {
}
}
return;
}
};

View File

@ -1,4 +1,4 @@
function getResponseHeader(xhr: XMLHttpRequest, responseHeader?: string): string | undefined {
const getResponseHeader = (xhr: XMLHttpRequest, responseHeader?: string): string | undefined => {
if (responseHeader) {
const content = xhr.getResponseHeader(responseHeader);
if (isString(content)) {
@ -6,4 +6,4 @@ function getResponseHeader(xhr: XMLHttpRequest, responseHeader?: string): string
}
}
return;
}
};

View File

@ -5,7 +5,7 @@ import type { ApiRequestOptions } from './ApiRequestOptions';
import type { ApiResult } from './ApiResult';
import { CancelablePromise } from './CancelablePromise';
import type { OnCancel } from './CancelablePromise';
import { OpenAPI } from './OpenAPI';
import { OpenAPIConfig } from './OpenAPI';
{{>functions/isDefined}}
@ -60,20 +60,21 @@ import { OpenAPI } from './OpenAPI';
/**
* Request using XHR client
* @param config The OpenAPI configuration object
* @param options The request options from the service
* @returns CancelablePromise<T>
* @throws ApiError
*/
export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions): CancelablePromise<T> => {
return new CancelablePromise(async (resolve, reject, onCancel) => {
try {
const url = getUrl(options);
const url = getUrl(config, options);
const formData = getFormData(options);
const body = getRequestBody(options);
const headers = await getHeaders(options);
const headers = await getHeaders(config, options);
if (!onCancel.isCancelled) {
const response = await sendRequest(options, url, formData, body, headers, onCancel);
const response = await sendRequest(config, options, url, formData, body, headers, onCancel);
const responseBody = getResponseBody(response);
const responseHeader = getResponseHeader(response, options.responseHeader);
@ -93,4 +94,4 @@ export function request<T>(options: ApiRequestOptions): CancelablePromise<T> {
reject(error);
}
});
}
};

View File

@ -1,14 +1,15 @@
async function sendRequest(
export const sendRequest = async (
config: OpenAPIConfig,
options: ApiRequestOptions,
url: string,
formData: FormData | undefined,
body: any,
headers: Headers,
onCancel: OnCancel
): Promise<XMLHttpRequest> {
): Promise<XMLHttpRequest> => {
const xhr = new XMLHttpRequest();
xhr.open(options.method, url, true);
xhr.withCredentials = OpenAPI.WITH_CREDENTIALS;
xhr.withCredentials = config.WITH_CREDENTIALS;
headers.forEach((value, key) => {
xhr.setRequestHeader(key, value);
@ -22,4 +23,4 @@ async function sendRequest(
onCancel(() => xhr.abort());
});
}
};

View File

@ -37,7 +37,7 @@ export class {{{name}}}{{{@root.postfix}}} {
* @throws ApiError
*/
public static {{{name}}}({{>parameters}}): CancelablePromise<{{>result}}> {
return __request({
return __request(OpenAPI, {
method: '{{{method}}}',
path: `{{{path}}}`,
{{#if parametersCookie}}