Introduction
Sometimes, our applications can get really crazy. Especially when your backend API calls become abundant in numbers. Here's how I managed to organize my API calls better -- Specifically, in React!
The Problem
When we make API calls, the most common method is a fetch
request. Some people use axios
(which is really great!), but I'm going to keep things mostly vanilla today. π
A common fetch request, such as a POST
, looks like this:
fetch("https://some-website.com/some-api-data", {
method: "POST",
headers: {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: "someRandomTokenHere-bckjhbdhkcjbdh"
},
body: JSON.stringify({data: {someDataKey: someDataValue}})
})
.then(resp => resp.json())
.then(resp => performSomeFunc())
.catch(error => console.log(error))
Now, I get it! Copy & Paste can be really useful here. (Thanks Larry Tesler! π RIP). But, why do that when we could do something better? Something that could cut down on code clutter... make things pretty... like, a Function API!
What is a function API?
Simply put -- It's an API of functions!
Check this out below. In my React project, I've created a folder under src
called services
. In services
is a JavaScript file named api.js
:
export const API_ROOT = "http://localhost:3000/api/v1"
const token = () => localStorage.getItem("token");
const headers = () => {
return {
"Content-Type": "application/json",
Accept: "application/json",
Authorization: token()
};
};
// data will be nested objects... ex. {user: {id: ...}}
const login = data => {
return fetch(`${API_ROOT}/login`, {
method: "POST",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json());
}
const newUser = data => {
return fetch(`${API_ROOT}/users`, {
method: "POST",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json())
}
const getCurrentSession = () => {
return fetch(`${API_ROOT}/current_session`, {
headers: headers()
}).then(resp => resp.json());
};
const updateUser = data => {
return fetch(`${API_ROOT}/users/${data.user.id}`, {
method: "PUT",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json());
};
const getUserList = data => {
return fetch(`${API_ROOT}/users/${data.user.id}/list`, {
method: "POST",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json())
};
const getUserListByUrl = data => {
return fetch(`${API_ROOT}/users/public/list`, {
method: "POST",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json())
};
const addToUserList = data => {
return fetch(`${API_ROOT}/users/list/add`, {
method: "POST",
headers: headers(),
body: JSON.stringify(data)
}).then(resp => resp.json())
};
const deleteUser = user_id => {
return fetch(`${API_ROOT}/users/${user_id}`, {
method: "DELETE",
headers: headers(),
}).then(resp => resp.json());
};
const deleteItem = listitem_id => {
return fetch(`${API_ROOT}/listitem/${listitem_id}/delete`, {
method: "DELETE",
headers: headers(),
}).then(resp => resp.json())
};
export const api = {
auth: {
login,
getCurrentSession,
},
user: {
newUser,
updateUser,
deleteUser,
getUserList,
},
list: {
getUserList,
getUserListByUrl,
addToUserList,
deleteItem,
}
}
You'll notice right at the bottom that I've created an API / data structure containing all of our functions in organized categories. Now, we can catch a glimpse of how much cleaner this will make our code!
componentWillUpdate()
and Function APIs
Assuming we want to check a user's session (if they are logged in), this is what our functional component might look like:
import React, {useEffect} from 'react';
import { api } from '../services/api.js'
export default function dashboard(data) {
const validateUserSession = () => {
// some unique code here that validates a user in your app
}
useEffect(() => {
api.auth.getCurrentSession()
.then(resp => validateUserSession())
})
return (
<div>
<p>If you're reading this, you're awesome!</p>
</div>
)
}
Wonderful! Our useEffect
hook runs when the page loads which executes a much more drawn out process (one that we defined in our Function API). It's CLEAN, it's DRY, and it's much more readable on a team.
Conclusion
I think this is one of the most useful methods for maintaining many API calls. Without them, it's easy to lose track of each call or even waste time typing them out or finding them somewhere else you already used them! Ahh, the headaches involved... but, I hope that you guys can take this and run with it! It makes us all better developers. π
Happy Tuesday!
Top comments (3)
Why use post and not get in some methods like getUserList ?
In that specific case, I have dynamic URLs setup in the project I'm developing based on users. So, you would travel to
domain.com/profile/username
and the website would takeusername
and query the database for that user's list. π If it was just to get the signed-in user's list, aGET
would work just fine. But I have to pass information in that exists outside of any session before I get results.understand