client-http-api-request-builder
Version:
A client for manage api request for frontend applications
203 lines (199 loc) • 6.49 kB
JavaScript
// src/api-builder.ts
import merge from "lodash/merge";
// src/request.ts
import axios from "axios";
import isArray from "lodash/isArray";
import reduce from "lodash/reduce";
import replace from "lodash/replace";
var toQueryString = (params) => (
// Use lodash's reduce function to iterate over each key-value pair in the params object
reduce(
params,
(result, value, key) => {
if (value === void 0 || key === void 0) {
return result;
}
if (isArray(value) && value.length > 0) {
const resultString = reduce(
value,
(result2, valueItem) => {
valueItem = replace(valueItem, new RegExp("#", "g"), "%23");
valueItem = replace(valueItem, new RegExp("['\u2019]", "g"), "%27");
return `${result2}${result2 === "" ? "" : "&"}${key}=${valueItem}`;
},
""
);
return `${result}${result === "" ? "?" : "&"}${resultString}`;
}
value = replace(value, new RegExp("#", "g"), "%23");
value = replace(value, new RegExp("['\u2019]", "g"), "%27");
return `${result}${result === "" ? "?" : "&"}${key}=${value}`;
},
""
)
);
async function getRequestHeaders(options) {
const headers = {
"Content-Type": "application/json",
// Spread operator is used to include any additional headers passed in options
...options.headers
};
return headers;
}
async function makeRequest(url, options) {
let response;
const requestHeaders = await getRequestHeaders(options);
const requestOptions = {
url,
method: options.method || "GET",
headers: Object.entries(requestHeaders).reduce((headers, [key, value]) => {
headers[key] = value.toString();
return headers;
}, {}),
data: options.body,
cancelToken: options.cancelToken
};
if (options.formData) {
requestOptions.headers["Content-Type"] = "multipart/form-data";
}
if (options.formData) {
response = await fetch(url, { body: options.body, ...requestOptions });
if (response.status < 200 || response.status > 299) {
throw response;
}
const parseResponse = await response.json();
response = { data: parseResponse };
} else {
response = await axios(requestOptions);
}
if (response.status < 200 || response.status > 299) {
throw response;
}
return response;
}
async function apiRequest(url, options) {
var _a, _b, _c;
try {
const response = await makeRequest(url, options);
if (response.status === 204) {
return true;
}
return response.data;
} catch (error) {
const response = error.response || error || {};
const getEndpoint = (url2) => url2.substring(
url2.length,
url2.indexOf("?") > -1 ? url2.indexOf("?") : void 0
);
const endpoint = url.includes(getEndpoint(url)) ? getEndpoint(url) : "external endpoint";
const errorMessage = `Received ${response.status} from ${(_a = error == null ? void 0 : error.request) == null ? void 0 : _a._method} request to ${endpoint}`;
console.log(`${errorMessage}`, {
url,
status: response.status,
error: (_b = response == null ? void 0 : response.data) == null ? void 0 : _b.error,
message: (_c = response == null ? void 0 : response.data) == null ? void 0 : _c.message,
method: options.method,
headers: options.headers
});
throw error;
}
}
// src/restEntityApi.ts
var RestEntityAPI = (options) => {
const { endpoint, selection, headers } = options;
const buildEndpoint = (endpoint2, params) => Array.isArray(params) ? endpoint2(...params) : endpoint2(params);
const create = async (data, params, cancelToken, query) => apiRequest(`${buildEndpoint(endpoint, params)}${toQueryString(query)}`, {
method: "POST",
body: data,
cancelToken,
headers,
...selection
});
const update = async (id, data, params) => apiRequest(`${buildEndpoint(endpoint, params)}/${id}`, {
method: "PUT",
body: data,
headers,
...selection
});
const destroy = async (id = "", params) => apiRequest(`${buildEndpoint(endpoint, params)}/${id}`, {
method: "DELETE",
headers,
...selection
});
const getById = async (id, params, query = null, cancelToken) => apiRequest(
`${buildEndpoint(endpoint, params)}/${id}${toQueryString(query)}`,
{ method: "GET", cancelToken }
);
const list = async (query, params, cancelToken) => apiRequest(`${buildEndpoint(endpoint, params)}${toQueryString(query)}`, {
method: "GET",
cancelToken,
headers,
...selection
});
return {
create,
update,
destroy,
getById,
list,
buildEndpoint,
toQueryString
};
};
var restEntityApi_default = RestEntityAPI;
// src/api-builder.ts
var METHOD_TYPES = {
POST: "POST",
PUT: "PUT",
DELETE: "DELETE",
GET: "GET",
LIST: "GET"
};
var API_METHODS = {
[METHOD_TYPES.POST]: "create",
[METHOD_TYPES.PUT]: "update",
[METHOD_TYPES.DELETE]: "destroy",
[METHOD_TYPES.GET]: "getById",
[METHOD_TYPES.LIST]: "list"
};
var ApiBuilder = (options) => {
const {
entities,
endpoints,
name,
endpoint,
headers
} = options;
const getApiEndpoints = (endpoints2) => {
let apiEndpoints = {};
let apiEntities = {};
const getMethods = (properties, isEntity, headerOptions) => (
// Use Object.keys and reduce to iterate over each property
Object.keys(properties).reduce((methods, methodName) => {
const { endpoint: endpoint2, type, selection } = properties[methodName];
const api = restEntityApi_default({ name: methodName, endpoint: endpoint2, selection, headers: headerOptions });
methods[methodName] = isEntity ? api : api[API_METHODS[type]];
return methods;
}, {})
);
if (name && endpoint) {
apiEntities = restEntityApi_default({ name, endpoint, headers });
} else if (entities && Object.keys(entities).length) {
apiEntities = getMethods(entities, true, headers);
} else if (endpoints2 && Object.keys(endpoints2).length) {
apiEndpoints = getMethods(endpoints2, false, headers);
}
return merge({}, { ...apiEndpoints }, { ...apiEntities });
};
return { ...getApiEndpoints(endpoints) };
};
var api_builder_default = ApiBuilder;
// index.ts
var client_http_api_request_builder_default = api_builder_default;
export {
METHOD_TYPES,
client_http_api_request_builder_default as default,
apiRequest as request,
toQueryString
};
//# sourceMappingURL=index.js.map