How to Create a Custom Request Model in React Using RxJs, TypeScript, and Fetch
By: Rogelio Monteagudo
Tags: JavaScript, Typescript, React, Reactjs, Programming

How to Create a Custom Request Model in React Using RxJs, TypeScript, and Fetch

Make your API requests easier

Image source: Author

Shifting from Angular to React wasn’t an easy transition. That was not due to the difference in difficulty between frameworks, but because I knew how much I’d miss the seamless TypeScript integration, along with Services and Pipes, but most of all potentially having to abandon RxJs. That is, until I did some research and realized I wouldn’t have to. So in this article, we’ll be looking at how to implement a base model for using the Fetch API already provided by JavaScript, along with TypeScript and RxJs for some flavor.

To get things started, let’s begin by creating a fresh React project with TypeScript support off the bat using the command:

npx create-react-app rxjs-react --template typescript

If you’d like to add TypeScript support to a current React project, please refer to this link: https://create-react-app.dev/docs/adding-typescript/

After that has been set up, switch to the root directory of your project and run this command to install RxJs:

npm i rxjs

Upon installation we’re good to go. You can now open the project in your preferred code editor and begin coding. Below is the structure we’ll be following for our files within our project. Please note that these will have to go under our src folder.

-services

|-api.service.ts

|-index.ts -utils

|-types.ts

|-base-request-model.ts

We’ll start off with creating our types.ts . Here we’ll be declaring the allowed types we’ll be using when performing our fetch requests.

Next, we’ll be creating our base-request-model.ts . This is the model we’ll be using to make any request coming from our app. We then import these types into our BaseRequestModel like so:

import { Method, _Headers, Body } from "./types";

For this example, we’ll be using http://dummy.restapiexample.com/api/v1 as our baseUrl and setting our default method to GET in our constructor. We’ll also be implementing our own interface for the properties. The model will have the following:

const baseUrl = 'http://dummy.restapiexample.com/api/v1'; interface Props {

url: string;

method?: Method;

headers: _Headers,

body?: Body

}

We’re making the body optional in the event that we’re making a get request and we don’t supply a body. We then implement the interface by using the keyword “implements” followed by the interface name after our class name. We then create a method that returns an observable, but before that, we’ll have to import the observable interface into our file in order to use it.

import {Observable} from 'rxjs'

Then we initialize our properties in the BaseModel contructor. A constructor is basically a special method that is used to initialize objects and is called as an object of a class is instantiated.

Then we implement the request method. Inside this method is where we’ll be using the built-in Fetch API:

https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

We’ll be returning the resolved promise wrapped in a new observable where we pass our values using the next() method provided by the observable and closing the stream using complete() . We can also throw errors using the error() method, similar to how promises use resolve() and reject() .

And that’s it for the BaseRequestModel . Below is the complete implementation.

Next, we’ll be creating our api.service.ts . Here we’ll be declaring our own fetch methods and returning an observable, as well as creating any custom headers we might need to pass. For now, we’ll be focusing only on post and get , but feel free to add your own methods and develop further if need be.

First, we’ll import our BaseRequestModel previously created and the Body interface declared in our types.ts .

import BaseRequestModel from '../utils/base-request-model';

import { Body } from '../utils/types';

Then we implement our get method wrapped in an object so we can easily access them, like so:

const ApiService = {

get: (route: string): Observable<any> => {

const headers = {

'Access-Control-Allow-Origin': '*'

};

const newBase = new BaseRequestModel(route, 'GET', headers);

return newBase.request();

},

}

What we’re basically doing here is creating a new instance of our BaseRequestModel . We’re passing the route, the method, and the headers defined by our constructor and then returning the request() method property, which is an observable stream we can subscribe to later to access the values of the request we made.

We repeat this for our post method, with the exception of a form parameter, which will be of type Body that we imported from our types and content type of application/json in our headers. We then pass the form into our new BaseRequestModel (this is why we made the body optional).

To conclude this part, we’ll export these methods with our index.ts , which we’ll be creating at the root of our services folder. We just need to add the export keyword to our ApiService variable. Below is the complete implementation.

Finally, we can test this by simply importing ApiService from our services into any component we’d like to make any fetch methods from.

import { ApiService } from "./services";

For now, we’ll be using this in our App.tsx . We’ll start by creating an interface for our employee.

interface Employee {

id: string;

employee_name: string;

employee_salary: string;

employee_age: string;

profile_image?: string;

}

The Elvis operator “?” indicates that the profile_image property will be optional, and we don’t have to assign a value to it. We’ll start with the get request. You can place this in a function and call it when need be, but for now, we’ll be using this in our useEffect() .

Note that on mount, we’re assigning our subscription to a value so we can easily unsubscribe from our observable on cleanup as our component unmounts. We’re also using the take() operator imported from ‘rxjs/operators’ and passing (1) so that we only get the first result of the stream, as well as the map() operator to manipulate any data received before assigning it to any value within the component. In this case, I only want the res.data being returned from the response.

We then map the results on our template and add some styling to each div note to declare the style object outside the scope of your component.

This will be the result:

We then include a button to test adding of an employee, along with the appropriate style declared outside the scope of the component.

We then define our addEmployee function.

We’ll be passing an object with the id, age, salary, and name of the employee to our post method from our ApiService and then pushing this object to the front of our employee array upon successful subscription or a successful post request. Save, and then click the Add Employee button to see the new employee prepended to our list of employees.

Ben Solo has joined the list

Below is the complete implementation.