DEV Community

Cover image for DIY Function APIs
Matthew Palmer
Matthew Palmer

Posted on

DIY Function APIs

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))
Enter fullscreen mode Exit fullscreen mode

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,
    }
}
Enter fullscreen mode Exit fullscreen mode

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>
    )
}
Enter fullscreen mode Exit fullscreen mode

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)

Collapse
 
lucasfrutig0 profile image
lucasfrutig0

Why use post and not get in some methods like getUserList ?

Collapse
 
matthewpalmer9 profile image
Matthew Palmer

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 take username and query the database for that user's list. 🙂 If it was just to get the signed-in user's list, a GET would work just fine. But I have to pass information in that exists outside of any session before I get results.

Collapse
 
lucasfrutig0 profile image
lucasfrutig0

understand