Mongez Http, A Axios Based package to manage http requests better than you do in your projects
Tags: http, ajax, node, react
Published: 2022-09-02 21:23:24

---
title: Mongez Http, A Axios Based package to manage http requests better than you do in your projects
published: true
description: 
tags: http, ajax, nodejs, reactjs
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
---

## Introduction

As mentioned in the title, the [Mongez http package)(<https://github.com/hassanzohdy/mongez-http>) is Axios based library to manage your ajax requests (and node js as well) but in a professional manner.

> This package is built on [Axios](https://www.npmjs.com/package/axios) so if you're good with Axios you will be familiar with the rest of the article.

## Installation

Using npm

`npm i @mongez/http`

Using Yarn

`yarn add @mongez/http`

Once the installation is done, create a `http-config.ts` file in your project (or .js, typescript is recommended though) so we can set our configurations.

> import the file in an early stage of your project, at the start of the `src/index.ts` for example or in your main project file entry.

Let's define our config file.

```ts
// http-config.ts
import { setHttpConfigurations } from '@mongez/http';

setHttpConfigurations({
    baseUrl: 'https://jsonplaceholder.typicode.com',    
});
```

For the demonstration purpose, we will use [JSON Placeholder API](https://jsonplaceholder.typicode.com) so you can see actual results.

We're good for the time being, now let's try to make some nice requests.

> You can follow up with what's going on in [Sandbox](https://codesandbox.io/s/react-typescript-forked-d5ksrr?file=/src/App.tsx)

## The endpoint handler

Once we set our configurations, now we can use our `endpoint` handler which can be used anywhere in your application.

What is endpoint handler? basically an axios instance but with some modifications.

To make our project clean and more structured let's create a `services` directory in your src project, inside it we'll add `todo-service.ts` file.

```ts
// todo-service.ts
import endpoint from "@mongez/http";

export function getTodoList() {
  return endpoint.get("/todo");
}
```

So what we've done is we imported the endpoint handler and exported a function to get the Todo list.

As you can see, we just added in the get method only the relative path to the base api url `/todo` so you don't have to put your base url in every request.

## Usage

Now we've set our configurations, handled our services, let's use it.

in your `App.ts` or if you're using react in the `useEffect` hook call the endpoint service.

```ts
// App.ts
import { getTodoList } from 'src/services/todo-service';

// let's make an ajax call

getTodoList().then((response) => {
  console.log(response.data);
});
```

## Posting data

We've seen how to work with **GET** requests, now let's see how to deal with **POST** requests.

For demo only i'll use React to make a simple create account pages.

```tsx
// RegisterPage.tsx
export default function RegisterPage() {
  return (
    <>
      <form>
        <input name="name" type="text" placeholder="Your Name" />
        <br />
        <input name="email" type="email" placeholder="Email Address" />
        <br />
        <input name="password" type="password" placeholder="Password" />
        <br />
        <button>Create Account</button>
      </form>
    </>
  );
}
```

We just made a simple basic ui to preview the create account form, now to submit the form, we need to get the data that will be sent, but before that let's make the `auth-service.ts` file in our **services** directory.

```ts
// src/services/auth-service.ts
import endpoint from "@mongez/http";

export function register(data: any) {
    return endpoint.post('/users', data);
}
```

We create the register handler now let's head back again to our ui.

```tsx
// RegisterPage.tsx
import { useState } from "react";
import { register } from "./services/auth-service";

export default function RegisterPage() {
  const [data, setData] = useState({
    email: "",
    name: "",
    password: ""
  });

  const createAccount = (e: any) => {
    e.preventDefault();

    register(data).then((response) => {
      console.log(response.data);
    });
  };

  return (
    <>
      <form onSubmit={createAccount}>
        <input
          name="name"
          onChange={(e) => {
            setData({
              ...data,
              name: e.target.value
            });
          }}
          type="text"
          placeholder="Your Name"
        />
        <br />
        <input
          onChange={(e) => {
            setData({
              ...data,
              email: e.target.value
            });
          }}
          name="email"
          type="email"
          placeholder="Email Address"
        />
        <br />
        <input
          onChange={(e) => {
            setData({
              ...data,
              password: e.target.value
            });
          }}
          name="password"
          type="password"
          placeholder="Password"
        />
        <br />
        <button>Create Account</button>
      </form>
    </>
  );
}
```

We made a simple state to store our form data inside it so we can send the object to the server, after submission you'll see console logging the same data that we filled as the api server returns the same data with an id, usually `11`.

### Form Data And Uploads

That was okay and good, but what if we want to upload files or images? in that case we will have to use [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData), however, this is not necessary as the package handles this for you, le'ts enhance our code a little bit.

> Please note this will not work as JSON Placeholder accepts only json but not [form-data](https://swagger.io/docs/specification/describing-request-body/multipart-requests/) requests.

```tsx
// RegisterPage.tsx
import { register } from "./services/auth-service";

export default function RegisterPage() {
  const createAccount = (e: any) => {
    e.preventDefault();

    // as you can see we skipped the state to store the data as we'll fetch it from the form inputs directly
    const formData = new FormData(e.target);

    register(formData).then((response) => {
      console.log(response.data);
    });
  };

  return (
    <>
      <form onSubmit={createAccount}>
        <input
          name="name"
          type="text"
          placeholder="Your Name"
        />
        <br />
        <input
          name="email"
          type="email"
          placeholder="Email Address"
        />
        <br />
        <input
          name="password"
          type="password"
          placeholder="Password"
        />
        <br />
        <button>Create Account</button>
      </form>
    </>
  );
}
```

Now we've sent a form data request, as mentioned earlier it can be done easier by just passing the form element `The e.target element` directly to the endpoint.

```tsx
// RegisterPage.tsx
import { register } from "./services/auth-service";

export default function RegisterPage() {
  const createAccount = (e: any) => {
    e.preventDefault();

    register(e.target).then((response) => {
      console.log(response.data);
    });
  };

  return (
    <>
      <form onSubmit={createAccount}>
        <input
          name="name"
          type="text"
          placeholder="Your Name"
        />
        <br />
        <input
          name="email"
          type="email"
          placeholder="Email Address"
        />
        <br />
        <input
          name="password"
          type="password"
          placeholder="Password"
        />
        <br />
        <button>Create Account</button>
      </form>
    </>
  );
}
```

Now we handled posting data to serer using three methods:

1. Passing `Plain` objects.
2. Passing `FormDta` objects.
3. Passing `FormElement` objects.

## The Restful Endpoint

Another powerful feature of Mongez Http is the `Restful class` that manages multiple requests within a class.

Let's head back to our todo-service.ts again and add a Restful endpoint class to mange it.

```ts
// todo-service.ts
import endpoint, { RestfulEndpoint } from "@mongez/http";

class TodoService extends RestfulEndpoint {
  /**
   * {@inheritDoc}
   */
  public route = "/todos";
}

const todoService: TodoService = new TodoService();

export default todoService;

// will be kept only for the demo
export function getTodoList() {
  return endpoint.get("/todos");
}
```

Now what was that?, well, basically the `RestfulEndpoint` class manages the main restful api requests in 6 major methods

- `list(queryStringParams: any)`: to get list of data, will make **GET** `/todos` request.
- `get(id: number | string)`: to get single record/data. will make **GET** `/todos/:id` request.
- `create(data: any)`: create a new record, will make **POST** `/todos` request.
- `update(id: number | string, data: any)`: update existing record, will make **PUT** `/todos/:id` request.
- `patch(id: number | string, data: any)`: perform patches over a record, will make **PATCH** `/todos/:id` request.
- `delete(id: number | string)`: delete record, will make **DELETE** `/todos/:id` request.

let's see how to use it in our real world code.

```ts
// TodoList.tsx
import { useEffect, useState } from "react";
import todoService from 'src/services/todo-service';

export default function TodoList() {
  const [items, setItems] = useState([]);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
    todoService.list().then((response) => {
      setItems(response.data);
      console.log(response.data);
      setLoading(false);
    });    
  }, []);

  if (isLoading) return <h1>Loading....</h1>;

  return (
    <>
      {items.map((item) => (
        <div key={item.id}>{item.title}</div>
      ))}
    </>
  );
}
```

We just called the `list` method to make a request,

We can also defines query params to the list request by passing an object to it, for example

```ts
todoService.list({
    limit: 15,
    active: 1,
}); // will make GET /todos?limit=15&active=1
```

To get a single record, the `service.get()` method will achieve this for you.

```ts
const todoId = 1;

todoService.get(todoId).then(response => {
    console.log(response.data);
});
```

## Aborting Requests

Another good feature is whether you want to catch the request in a variable so you may abort/cancel it anytime you like, for example when sending request in useEffect, we can use the `lastRequest` feature to achieve this.

```tsx
// TodoList.tsx
import { lastRequest } from "@mongez/http";
import { useEffect, useState } from "react";
import todoService from 'src/services/todo-service';

export default function TodoList() {
  const [items, setItems] = useState([]);
  const [isLoading, setLoading] = useState(true);

  useEffect(() => {
    todoService.list().then((response) => {
      setItems(response.data);
      console.log(response.data);
      setLoading(false);
    });
      .catch((error) => {
        console.log(error);
      });

    // catch the request
    let request = lastRequest();
    
    return () => {
      request.abort();
    };
  }, []);

  if (isLoading) return <h1>Loading....</h1>;

  return (
    <>
      {items.map((item) => (
        <div key={item.id}>{item.title}</div>
      ))}
    </>
  );
}
```

## Put To Post

In some languages such as PHP, you can not directly upload files or images using `PUT` request method, alternatively some frameworks like [Laravel](https://laravel.com/) made a workaround to solve this issue by making `POST` request with `_method` key paired with `PUT` as its value so you can listen to the request as `PUT` request, this also can be the same here by setting the `putToPost` key in the http configurations to true but your code will still the same.

Before using the request will be something like

```ts
// some-service.ts
import endpoint from '@mongez/http';

export function updateProfile(data: any) {
    return endpoint.put('/me', data); 
}

updateProfile({
    username: 'hasan',
    password: '123'
}); 

// PUT /me request and { username: hasan, password: 123 } as data
```

Now let's active the flag.

```ts
// http-config.ts

import { setHttpConfigurations } from '@mongez/http';

setHttpConfigurations({
    baseUrl: 'https://jsonplaceholder.typicode.com',    
    putToPost: true,
});
```

After activating it

```ts
// some-service.ts
import endpoint from '@mongez/http';

export function updateProfile(data: any) {
    return endpoint.put('/me', data); 
}

updateProfile({
    username: 'hasan',
    password: '123'
}); 

// PUT /me request and { username: hasan, password: 123, _method: PUT } as data
```

So you won't change anything in your code, and if your api ever would neglect this feature and allow direct uploads, you just disable the flag and we're all good.

## HTTP Events / Interceptors

The last feature that i'd like to talk about is The request events or interceptors, this is extremely helpful way to manipulate the requests before it is sent or even the response when it is done.

This can be done using `endpointEvents` handler, it provides 4 good interceptors to work with.

1. `beforeSending` interceptor: triggered before sending the request and allows you to modify any request before it's started, like adding additional headers, modify data and so on.
2. `onSuccess` interceptor: triggered after the response is sent and its a success response with status code like `200` or `200`, can be used to modify the response data before you use it in your actual code for example before using it in your component calls.
3. `onError` interceptor: triggered after the response is sent and its a failure response with status code like `400` or `500`, this can be useful with `401` requests if the user has no longer access to the project at anytime you can log the user off.
4. `onResponse` interceptor: triggered after the response is sent wether it is success or failed, can be used for requests logging or whatever you want.

The `beforeSending` interceptor receives the axios request config for its callback, we can for example set the `Authorization` header.

```ts
import { AxiosRequestConfig } from "axios";
import { AxiosRequestConfig } from "axios";
import { endpointEvents } from '@mongez/http';

// This is triggered before sending any request
endpointEvents.beforeSending((config: AxiosRequestConfig): EventSubscription => {
    config.headers.Authorization = 'key xxx';
});
```

## Conclusion

The package main purpose is to make your code organized, well structured and easy to maintain or scale, as mentioned earlier its based on Axios so any feature you might need to use in Axios can be used here as well.

For more detailed documentation about the package, feel free to visit [the Github repository](https://github.com/hassanzohdy/mongez-http).

I hope you enjoy the package and any feedback is appreciated.

Enjoy and happy coding.