Created
August 5, 2021 20:06
-
-
Save tranquan/5812d7e57d32ce28e28043766c4c0088 to your computer and use it in GitHub Desktop.
A simple API client for react, react-native
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { handleError } from "./errorHandler"; | |
import { stringify } from "qs"; | |
let BASE_URL = "http://localhost:8000/api/"; | |
interface ClientConfig { | |
baseUrl?: string; | |
} | |
export function configureClient(configs: ClientConfig) { | |
if (configs.baseUrl) { | |
BASE_URL = configs.baseUrl; | |
} | |
} | |
export function getClientConfig() { | |
return { | |
baseUrl: BASE_URL, | |
}; | |
} | |
interface StringMap { | |
[k: string]: string; | |
} | |
export interface GetOptions { | |
queryData: {}; | |
headers: StringMap; | |
} | |
export interface BodyRequestOptions { | |
data: {}; | |
isFormData: boolean; | |
headers: StringMap; | |
} | |
function serialize(obj: object): string { | |
return stringify(obj, { allowDots: true }); | |
} | |
function initRequest(): RequestInit { | |
return { | |
mode: "cors", | |
cache: "default", | |
credentials: "same-origin", | |
headers: { | |
Accept: "application/json, */*", | |
"Content-Type": "application/json;charset=UTF-8", | |
}, | |
}; | |
} | |
/** | |
* Fetch: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API | |
* Request: https://developer.mozilla.org/en-US/docs/Web/API/Request | |
*/ | |
function request(method: string, path: string, options: Partial<GetOptions & BodyRequestOptions> = {}): Promise<any> { | |
const fetchRequest = initRequest(); | |
fetchRequest.method = method; | |
if (options.isFormData) { | |
(fetchRequest.headers as any)["Content-Type"] = "application/form-data"; | |
fetchRequest.body = options.data as any; | |
} else if (Object.keys(options.data ?? {}).length > 0) { | |
(fetchRequest.headers as any)["Content-Type"] = "application/json;charset=UTF-8"; | |
fetchRequest.body = JSON.stringify(options.data); | |
} | |
const fetchUrl = BASE_URL + path; | |
return fetch(fetchUrl, fetchRequest) | |
.then(response => { | |
return handleError(response); | |
}) | |
.then(response => { | |
return response.json(); | |
}) | |
.then(data => { | |
// fake slow loading | |
// return new Promise((res, rej) => { | |
// setTimeout(() => { | |
// res(data); | |
// }, 2000); | |
// }); | |
// -- end | |
return data; | |
}) | |
.catch(error => { | |
console.log(`error:`, error); | |
throw error; | |
}); | |
} | |
export function getRequest(path: string, queryData: object = {}) { | |
return getRequestWithOptions(path, { queryData }); | |
} | |
export function getRequestWithOptions(path: string, options: Partial<GetOptions> = {}) { | |
const { queryData } = options; | |
let pathWithQueryString = path; | |
if (queryData && Object.keys(queryData).length > 0) { | |
pathWithQueryString += "?" + serialize(queryData); | |
} | |
return request("GET", pathWithQueryString, options); | |
} | |
export function postRequest(path: string, data: object = {}, isFormData: boolean = false) { | |
return request("POST", path, { data, isFormData }); | |
} | |
export function postRequestWithOptions(path: string, options: Partial<BodyRequestOptions> = {}) { | |
return request("POST", path, options); | |
} | |
export function deleteRequest(path: string, data: object = {}) { | |
return request("DELETE", path, { data }); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import EventEmitter from "src/services/eventEmitter"; | |
export class ApiError extends Error { | |
response: Response; | |
constructor(message: string, response: Response) { | |
super(message); | |
this.response = response.clone(); | |
} | |
static isApiError(error: any) { | |
return error && error.response && error.response instanceof Response; | |
} | |
} | |
export enum ApiEvents { | |
/** http status = 400 */ | |
BAD_REQUEST = "BAD_REQUEST", | |
/** http status = 401 */ | |
UN_AUTHORIZED = "UN_AUTHORIZED", | |
/** http status = 403 */ | |
FORBIDDEN = "FORBIDDEN", | |
/** http status = 302 */ | |
RESPONSE_REDIRECT = "RESPONSE_REDIRECT", | |
} | |
export function isResponseError(response: Response) { | |
if (response.status < 200 || response.status > 299) { | |
return true; | |
} | |
return false; | |
} | |
function _handleError(response: Response) { | |
switch (response.status) { | |
case 302: | |
EventEmitter.notify(ApiEvents.RESPONSE_REDIRECT, { url: response.url }); | |
break; | |
case 400: | |
EventEmitter.notify(ApiEvents.BAD_REQUEST, { url: response.url }); | |
break; | |
case 401: | |
EventEmitter.notify(ApiEvents.UN_AUTHORIZED, { url: response.url }); | |
break; | |
case 403: | |
EventEmitter.notify(ApiEvents.FORBIDDEN, { url: response.url }); | |
break; | |
} | |
} | |
export function handleError(response: Response): Response { | |
if (isResponseError(response)) { | |
_handleError(response); | |
const message = `status: ${response.status}; url: ${response.url}`; | |
throw new ApiError(message, response); | |
} | |
// No error => continue | |
return response; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment