generic functions for backend queries

This commit is contained in:
Aarni Halinen
2021-09-04 18:02:29 +03:00
parent d48c6a0c3e
commit efd916a8a2
13 changed files with 200 additions and 230 deletions
+122
View File
@@ -0,0 +1,122 @@
import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
import { getTokenCookie } from "@utils/auth";
export const HOST = `${process.env.NEXT_PUBLIC_API_URL}`;
const axiosInstance: AxiosInstance = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
});
export enum APIPath {
TAGS = "/tags/:id",
EVENTS = "/events/:id",
FEED = "/feed/:id",
JOBADS = "/jobads/:id",
SIGNUPS = "/signup/:id",
SIGNUP_FORMS = "/signupForm/:id",
AUTH_TOKEN = "/api-token-auth",
AUTH_TOKEN_VERIFY = "/api-token-verify",
}
export type API = {
path: APIPath;
urlParams?: {
id?: string | number;
};
queryParams?: {
limit?: number;
offset?: number;
since?: Date;
};
authenticated?: boolean;
};
type Headers = {
Authorization?: string;
};
const getAuthHeader = (): string => {
const jwt = getTokenCookie();
return `JWT ${jwt}`;
};
const getHeaders = (auth?: boolean): Headers => {
if (auth) {
return {
Authorization: getAuthHeader(),
};
}
return {};
};
const fillUrlParams = (apiPath: APIPath, params: API["urlParams"] = {}): string => {
const path = apiPath
.split("/")
.filter(Boolean)
.map((urlComponent) => {
// fill in each placeholder component like ':id' with value from params
if (urlComponent.startsWith(":")) {
const key = urlComponent.substring(1);
const value = params[key];
return value;
}
return urlComponent;
})
.join("/");
// code above strips leading '/' from path
return `/${path}`;
};
async function callBackendAPI<RequestType, ResponseType>(
path: APIPath,
urlParams: API["urlParams"] = {},
queryParams: API["queryParams"] = {},
method: AxiosRequestConfig["method"],
headers: Headers,
requestBody: RequestType,
): Promise<ResponseType> {
const url = fillUrlParams(path, urlParams);
const request: AxiosRequestConfig = {
url,
method,
headers,
params: queryParams,
data: requestBody,
responseType: "json",
};
const response = await axiosInstance.request<ResponseType>(request);
const arrayResp = (response.data as { results?: ResponseType });
if (Array.isArray(arrayResp.results)) {
return arrayResp.results;
}
return response.data;
}
export async function getBackendAPI<ResponseType>({
path, urlParams, queryParams, authenticated,
}: API): Promise<ResponseType> {
const headers = getHeaders(authenticated);
return callBackendAPI<undefined, ResponseType>(path, urlParams, queryParams, "GET", headers, undefined);
}
export async function postBackendAPI<RequestType, ResponseType>({
path, urlParams, queryParams, authenticated,
}: API, body: RequestType): Promise<ResponseType> {
const headers = getHeaders(authenticated);
return callBackendAPI<RequestType, ResponseType>(path, urlParams, queryParams, "POST", headers, body);
}
export async function putBackendAPI<RequestType, ResponseType>({
path, urlParams, queryParams, authenticated,
}: API, body: RequestType): Promise<ResponseType> {
const headers = getHeaders(authenticated);
return callBackendAPI<RequestType, ResponseType>(path, urlParams, queryParams, "PUT", headers, body);
}
export async function deleteBackendAPI<ResponseType>({
path, urlParams, queryParams, authenticated,
}: API): Promise<ResponseType> {
const headers = getHeaders(authenticated);
return callBackendAPI<undefined, ResponseType>(path, urlParams, queryParams, "DELETE", headers, undefined);
}
+25 -43
View File
@@ -1,11 +1,10 @@
/* eslint-disable no-console */
import axios from "axios";
import Event from "@models/Event";
import { getAuthHeader } from "@utils/auth";
import {
APIPath, deleteBackendAPI, getBackendAPI, postBackendAPI, putBackendAPI,
} from "./backend";
export const URL = `${process.env.NEXT_PUBLIC_API_URL}/events/`;
export interface Options {
interface Options {
limit?: number;
offset?: number;
auth?: boolean;
@@ -15,33 +14,28 @@ export interface Options {
class EventApi {
static async getEvent(id: number, auth = false): Promise<Event> {
try {
const headers = auth ? { Authorization: getAuthHeader() } : null;
const resp = await axios.get(`${URL}${id}/`, {
headers,
return await getBackendAPI({
path: APIPath.EVENTS, urlParams: { id }, authenticated: auth,
});
return resp.data;
} catch (err) {
console.error(err);
throw err;
}
}
static async getEvents(options: Options = {}): Promise<Event[]> {
const {
since, limit, offset, auth,
} = options;
static async getEvents({
since, limit, offset, auth,
}: Options = {}): Promise<Event[]> {
try {
const params = {
since,
limit,
offset,
};
const headers = auth ? { Authorization: getAuthHeader() } : null;
const resp = await axios.get(`${URL}`, {
headers,
params,
return await getBackendAPI<Event[]>({
path: APIPath.EVENTS,
queryParams: {
since,
limit,
offset,
},
authenticated: auth,
});
return resp.data.results;
} catch (err) {
console.error(err);
throw err;
@@ -50,12 +44,9 @@ class EventApi {
static async createEvent(data: Event): Promise<Event> {
try {
const resp = await axios.post(URL, data, {
headers: {
Authorization: getAuthHeader(),
},
});
return resp.data;
return await postBackendAPI<Event, Event>({
path: APIPath.EVENTS, authenticated: true,
}, data);
} catch (err) {
console.error(err);
throw err;
@@ -64,27 +55,18 @@ class EventApi {
static async updateEvent(data: Event): Promise<Event> {
try {
const putUrl = `${URL}${data.id}/`;
const resp = await axios.put(putUrl, data, {
headers: {
Authorization: getAuthHeader(),
},
});
return resp.data;
return await putBackendAPI<Event, Event>({
path: APIPath.EVENTS, urlParams: { id: data.id }, authenticated: true,
}, data);
} catch (err) {
console.error(err);
throw err;
}
}
static async deleteEvent(id: number) {
static async deleteEvent(id: number): Promise<void> {
try {
const resp = await axios.delete(`${URL}${id}`, {
headers: {
Authorization: getAuthHeader(),
},
});
return resp.data;
await deleteBackendAPI<{ message: "OK" }>({ path: APIPath.EVENTS, urlParams: { id } });
} catch (err) {
console.error(err);
throw err;