Creating an API resource file using axios

Creating an API resource file using axios

ยท

3 min read

Table of contents

No heading

No headings in the article.

At some point while developing, you will need to manipulate data from a backend service or server.

manipulating data can be of several forms:

  1. get a data from the backend
  2. sending data for further processing
  3. updating previous/stale data
  4. adding to previous data
  5. deleting data etc

In a REST architechture the common action verbs are GET, POST, PATCH, PUT, DELETE; this verbs helps both the frontend and the backend developer to understand what the user is trying to do

Two of the popular resource you can use to make request to backend are: fetch and axios; In this article, I will be explaining how to use axios to create a general API resource file which can later be used to make API calls:

import axios, {
 AxiosError, 
 AxiosInstance, 
 AxiosRequestConfig, 
 AxiosResponse 
} from 'axios';

const BASE_URL = 'https://backend.com/api/';

const getToken = async () => localStorage.getItem('token');
const removeToken = async () => localStorage.removeItem('token');

function ApiResource() {
    const api = axios.create({
        baseURL: BASE_URL,
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'Access-Control-Allow-Methods': '*',
            'Access-Control-Allow-Origin': BASE_URL,
        },
    }) as AxiosInstance;

    api.interceptors.request.use(
        async (config: AxiosRequestConfig) => {
            if (config?.headers) {
                const token = await getToken();
                if (!token) return config;

                config.headers['Authorization'] = `Bearer ${token}`;
                return config;
            }
        },
        (error: AxiosError) => Promise.reject(error)
    );

    api.interceptors.response.use(
        (response: AxiosResponse) => response,
        (error: AxiosError) => {
            const errorData = error?.response?.data as Record<string, string | object>;

            if (error.response === undefined) {
                // show a toast here
                console.log('Error: No internet connection!');
            } else {
                if (+errorData?.code === 401) {
                    const message = (errorData?.description || error?.message) as string;
                    // show a toast here
                    console.log('Error: ', message);
                    removeToken();
                    // return navigate(ROUTES.LOGIN);
                }
            }

            return Promise.reject(errorData);
        });

    return {
        get: (url: string) => api.get(url).then(({ data }) => data),

        post: (args: [string, object]) => api.post(...args).then(({ data }) => data),

        patch: (args: [string, object]) => api.patch(...args).then(({ data }) => data),

        put: (args: [string, object]) => api.put(...args).then(({ data }) => data),

        delete: (url: string) => api.delete(url).then(({ data }) => data),
    }
}

export const api = ApiResource();

api.ts

link to the github gist

How to use

import { yupResolver } from "@hookform/resolvers/yup";
import { Button, Input } from "components";
import { SubmitHandler, useForm } from "react-hook-form";
import { Link } from "react-router-dom";
import { loginSchema } from "schemas";
import { api } from 'utils';

type FormData = {
  email: string;
  password: string;
};

function LoginForm() {
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<FormData>({
    resolver: yupResolver(loginSchema),
  });
  const onSubmit: SubmitHandler<FormData> = async (data) => {
    const result = await api.post(["/login", data]);
    console.log(result);
  };

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <div className="mb-6">
        <Input
          type="email"
          label="Email Address"
          {...register("email")}
          error={errors?.email}
        />
      </div>

      <div className="mb-6">
        <Input
          type="password"
          label="Password"
          {...register("password")}
          error={errors?.password}
        />
      </div>

      <div className="mb-3">
        <Button text="Login" type="submit" />
      </div>

      <div className="flex justify-center items-center mb-6">
        <Link to="/forgot-password" className="text-gray-800">
          Forgot password?
        </Link>
      </div>

      <div className="text-center">
        <p className="text-sm font-semibold mt-2 pt-1 mb-0">
          Don't have an account?
          <Link
            to="/register"
            className="ml-2 text-red-600 hover:text-red-700 focus:text-red-700"
          >
            Register
          </Link>
        </p>
      </div>
    </form>
  );
}

export default LoginForm;

LoginForm.tsx

Thanks, for checking out this tutorial. (please like and add your comments) You can also check out my other tutorials on my blog

Special thanks to my friend a bad-ass frontend developer Casper for helping me review this ๐Ÿ™

If you have any questions, feedback or comments, please let me know.

You can connect with me on twitter email github

You can also reach out to me(I do React-Native & React Js) twitter email

ย