acacode / acacode/swagger-typescript-api
If an error occurs in a web call then it throws 'Response', it would be nice to be able to customize this behaviour
- 主要言語
- TypeScript
- スター
- 4.1k
- フォーク
- 436
- PR マージ指標
- 30日以内にマージされた PR はありません
説明
Converting the http response into the return data or an error takes place in
return fetch(requestUrl, requestOptions).then(async (response) => {
const data = await this.safeParseResponse(response);
if (!response.ok) throw data;
return data;
});
If this could be placed into a protected function, then its could be sub classed and overridden.
i.e.
```
return fetch(requestUrl, requestOptions).then(async (response) => {
return await this.handleResponse(response);
});
}
protected async handleResponse(response: Response): Promise> {
const data = await this.safeParseResponse(response);
if (!response.ok) throw data;
return data;
}
```
Note safeParseResponse also needs changing to protected, it may also be a good idea to export HttpResponse
Full Template.
```
export type RequestParams = Omit & {
secure?: boolean;
}
{{#hasQueryRoutes}}
export type RequestQueryParamsType = Record;
{{/hasQueryRoutes}}
interface ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> {
baseUrl?: string;
baseApiParams?: RequestParams;
securityWorker?: (securityData: SecurityDataType) => RequestParams;
}
{{#generateResponses}}
/** Overrided Promise type. Needs for additional typings of `.catch` callback */
type TPromise = Omit, "then" | "catch"> & {
then(onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: RejectType) => TResult2 | PromiseLike) | undefined | null): TPromise;
catch(onrejected?: ((reason: RejectType) => TResult | PromiseLike) | undefined | null): TPromise;
}
{{/generateResponses}}
interface HttpResponse extends Response {
data: D | null;
error: E | null;
}
enum BodyType {
Json,
{{#hasFormDataRoutes}}
FormData,
{{/hasFormDataRoutes}}
}
class HttpClient<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> {
public baseUrl: string = "{{apiConfig.baseUrl}}";
private securityData: SecurityDataType = (null as any);
private securityWorker: null | ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}>["securityWorker"] = null;
private baseApiParams: RequestParams = {
credentials: 'same-origin',
headers: {
'Content-Type': 'application/json'
},
redirect: 'follow',
referrerPolicy: 'no-referrer',
}
constructor(apiConfig: ApiConfig<{{#apiConfig.generic}}{{name}},{{/apiConfig.generic}}> = {}) {
Object.assign(this, apiConfig);
}
public setSecurityData = (data: SecurityDataType) => {
this.securityData = data
}
{{#hasQueryRoutes}}
private addQueryParam(query: RequestQueryParamsType, key: string) {
return encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key])
}
protected addQueryParams(rawQuery?: RequestQueryParamsType): string {
const query = rawQuery || {};
const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
return keys.length ? `?${keys.map(key =>
typeof query[key] === "object" && !Array.isArray(query[key]) ?
this.addQueryParams(query[key] as object).substring(1) :
this.addQueryParam(query, key)).join("&")
}` : "";
}
{{/hasQueryRoutes}}
private bodyFormatters: Record any> = {
[BodyType.Json]: JSON.stringify,
{{#hasFormDataRoutes}}
[BodyType.FormData]: (input: any) =>
Object.keys(input).reduce((data, key) => {
data.append(key, input[key]);
return data;
}, new FormData()),
{{/hasFormDataRoutes}}
}
private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams {
return {
...this.baseApiParams,
...params,
...(securityParams || {}),
headers: {
...(this.baseApiParams.headers || {}),
...(params.headers || {}),
...((securityParams && securityParams.headers) || {})
}
}
}
protected safeParseResponse = (response: Response): Promise> => {
const r = response as HttpResponse;
r.data = null;
r.error = null;
return response
.json()
.then((data) => {
if (r.ok) {
r.data = data;
} else {
r.error = data;
}
return r;
})
.catch((e) => {
r.error = e;
return r;
});
}
public request = (
path: string,
method: string,
{ secure, ...params }: RequestParams = {},
body?: any,
bodyType?: BodyType,
secureByDefault?: boolean,
): {{#generateResponses}}TPromise>{{/generateResponses}}{{^generateResponses}}Promise>{{/generateResponses}} => {
const requestUrl = `${this.baseUrl}${path}`;
const secureOptions = (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {};
const requestOptions = {
...this.mergeRequestOptions(params, secureOptions),
method,
body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null,
}
return fetch(requestUrl, requestOptions).then(async (response) => {
return await this.handleResponse(response);
});
}
protected async handleResponse(response: Response): Promise> {
const data = await this.safeParseResponse(response);
if (!response.ok) throw data;
return data;
}
}
```
コントリビューションガイド
このリポジトリのコントリビューションガイドは索引されていません
評価
この issue はまだ評価されていません。