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

Đang mở
#95 2 bình luận 6 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
TypeScript
Star
4.1k
Fork
436
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

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;
}
}

```

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.