Skip to content

Commit

Permalink
feat: add ofetch http client
Browse files Browse the repository at this point in the history
  • Loading branch information
samydoesit committed Mar 27, 2024
1 parent 2b6db23 commit 92f3a6d
Show file tree
Hide file tree
Showing 16 changed files with 70,668 additions and 3 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Options:
--disableStrictSSL disabled strict SSL (default: false)
--disableProxy disabled proxy (default: false)
--axios generate axios http client (default: false)
--ofetch generate ofetch http client (default: false)
--unwrap-response-data unwrap the data item from the response (default: false)
--disable-throw-on-error Do not throw an error when response.ok is not true (default: false)
--single-http-client Ability to send HttpClient instance to Api constructor (default: false)
Expand Down
2 changes: 1 addition & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {MonoSchemaParser} from "./src/schema-parser/mono-schema-parser";

type HttpClientType = "axios" | "fetch";
type HttpClientType = "axios" | "fetch" | "ofetch";

interface GenerateApiParamsBase {
/**
Expand Down
6 changes: 5 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,11 @@ const program = cli({
description: 'generate axios http client',
default: codeGenBaseConfig.httpClientType === HTTP_CLIENT.AXIOS,
},
{
flags: 'ofetch',
description: 'generate ofetch http client',
default: codeGenBaseConfig.httpClientType === HTTP_CLIENT.OFETCH,
},
{
flags: '--unwrap-response-data',
description: 'unwrap the data item from the response',
Expand Down Expand Up @@ -342,7 +347,6 @@ const main = async () => {
} catch (e) {
console.error(e);
process.exit(1);
return;
}
process.exit(0);
};
Expand Down
32 changes: 31 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,11 @@
"test:jsSingleHttpClientModular": "node tests/spec/jsSingleHttpClientModular/test.js",
"test:--js--axios": "node tests/spec/jsAxios/test.js",
"test:--axios": "node tests/spec/axios/test.js",
"test:--ofetch": "node tests/spec/ofetch/test.js",
"test:--another-array-type": "node tests/spec/another-array-type/test.js",
"test:--object-types": "node tests/spec/object-types/test.js",
"test:--axios--single-http-client": "node tests/spec/axiosSingleHttpClient/test.js",
"test:--ofetch--single-http-client": "node tests/spec/ofetchSingleHttpClient/test.js",
"test:--type-suffix--type-prefix": "node tests/spec/typeSuffixPrefix/test.js",
"test:--dot-path-params": "node tests/spec/dot-path-params/test.js",
"test:--primitive-type-constructs": "node tests/spec/primitive-type-constructs/test.js",
Expand Down Expand Up @@ -81,6 +83,7 @@
"@types/prettier": "^2.7.3",
"all-contributors-cli": "^6.26.1",
"axios": "^1.4.0",
"ofetch": "^1.3.4",
"cross-env": "^7.0.3",
"dotenv": "^16.3.1",
"git-diff": "^2.0.6",
Expand Down
1 change: 1 addition & 0 deletions src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const SCHEMA_TYPES = {

const HTTP_CLIENT = {
FETCH: 'fetch',
OFETCH: 'ofetch',
AXIOS: 'axios',
};

Expand Down
124 changes: 124 additions & 0 deletions templates/base/http-clients/ofetch-http-client.ejs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
<%
const { apiConfig, generateResponses, config } = it;
%>

import type { $Fetch, FetchOptions } from 'ofetch'
import { $fetch } from 'ofetch'

export type QueryParamsType = Record<string | number, any>;
export type ResponseFormat = keyof Omit<Body, "body" | "bodyUsed">;

export interface CustomFetchOptions extends FetchOptions {
/** set parameter to `true` for call `securityWorker` for this request */
secure?: boolean
}

export type RequestParams = Omit<CustomFetchOptions, 'body' | 'method'>

export interface ApiConfig<SecurityDataType = unknown> {
baseURL?: string;
basePath?: string;
baseSiteId?: string;
baseApiParams?: Omit<RequestParams, "baseURL" | "cancelToken" | "signal">;
securityWorker?: (securityData: SecurityDataType | null) => Promise<RequestParams | void> | RequestParams | void;
customFetch?: $Fetch;
}

type CancelToken = Symbol | string | number;

export enum ContentType {
Json = "application/json",
FormData = "multipart/form-data",
UrlEncoded = "application/x-www-form-urlencoded",
}

export class HttpClient<SecurityDataType = unknown> {
public baseURL: string = "<%~ apiConfig.baseUrl %>";
private securityData: SecurityDataType | null = null;
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
private abortControllers = new Map<CancelToken, AbortController>();
private customFetch = (url: string, fetchParams: FetchOptions) => $fetch(url, fetchParams)

private baseApiParams: RequestParams = {
credentials: 'same-origin',
headers: {},
redirect: 'follow',
referrerPolicy: 'no-referrer',
}

constructor(apiConfig: ApiConfig<SecurityDataType> = {}) {
Object.assign(this, apiConfig);
}

public setSecurityData = (data: SecurityDataType | null) => {
this.securityData = data;
}

protected mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams {
return {
...this.baseApiParams,
...params1,
...(params2 || {}),
headers: {
...(this.baseApiParams.headers || {}),
...(params1.headers || {}),
...((params2 && params2.headers) || {}),
},
};
}

protected createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => {
if (this.abortControllers.has(cancelToken)) {
const abortController = this.abortControllers.get(cancelToken);
if (abortController) {
return abortController.signal;
}
return void 0;
}

const abortController = new AbortController();
this.abortControllers.set(cancelToken, abortController);
return abortController.signal;
}

public abortRequest = (cancelToken: CancelToken) => {
const abortController = this.abortControllers.get(cancelToken)

if (abortController) {
abortController.abort();
this.abortControllers.delete(cancelToken);
}
}

public request = async <T = any>(url: string, {
body,
secure,
method,
baseURL,
signal,
params,
...options
<% if (config.unwrapResponseData) { %>
}: CustomFetchOptions): Promise<T> => {
<% } else { %>
}: CustomFetchOptions): Promise<T> => {
<% } %>
const secureParams = ((typeof secure === 'boolean' ? secure : this.baseApiParams.secure) && this.securityWorker && await this.securityWorker(this.securityData)) || {};
const requestOptions = this.mergeRequestParams(options, secureParams)

return this.customFetch(
`${baseURL || this.baseURL || ""}${this.basePath ? `${this.basePath}` : ''}${url}`,
{
params,
method,
...requestOptions,
signal,
body,
}
<% if (config.unwrapResponseData) { %>
).then((response: T) => response.data)
<% } else { %>
).then((response: T) => response)
<% } %>
};
}
7 changes: 7 additions & 0 deletions templates/default/procedure-call.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,20 @@ const describeReturnType = () => {

*/
<%~ route.routeName.usage %><%~ route.namespace ? ': ' : ' = ' %>(<%~ wrapperArgs %>)<%~ config.toJS ? `: ${describeReturnType()}` : "" %> =>
<% if (config.httpClientType === config.constants.HTTP_CLIENT.OFETCH) { %>
<%~ config.singleHttpClient ? 'this.http.request' : 'this.request' %><<%~ type %>>(`<%~ path %>`, {
<% } %>
<% if (config.httpClientType !== config.constants.HTTP_CLIENT.OFETCH) { %>
<%~ config.singleHttpClient ? 'this.http.request' : 'this.request' %><<%~ type %>, <%~ errorType %>>({
path: `<%~ path %>`,
<% } %>
method: '<%~ _.upperCase(method) %>',
<%~ queryTmpl ? `query: ${queryTmpl},` : '' %>
<%~ bodyTmpl ? `body: ${bodyTmpl},` : '' %>
<%~ securityTmpl ? `secure: ${securityTmpl},` : '' %>
<% if (config.httpClientType !== config.constants.HTTP_CLIENT.OFETCH) { %>
<%~ bodyContentKindTmpl ? `type: ${bodyContentKindTmpl},` : '' %>
<%~ responseFormatTmpl ? `format: ${responseFormatTmpl},` : '' %>
<% } %>
...<%~ _.get(requestConfigParam, "name") %>,
})<%~ route.namespace ? ',' : '' %>
Loading

0 comments on commit 92f3a6d

Please sign in to comment.