Separate Modules for Backend Communication

crrojas88

Rodrigo Rojas

Posted on June 14, 2021

Separate Modules for Backend Communication

In this (final?) installment of using axios to make HTTP requests, we've managed to make GET, POST & PUT requests. However, our code has started to chonkify a bit. So now I'm going to cover how to separate our backend communication into its own module.

We can start by creating a new directory called services inside our src folder. Create a file named contacts.js.

// src/services/contacts.js

import axios from 'axios';

const baseUrl = 'http://localhost3001/people'

const getAll = () => {
    const request = axios.get(baseUrl)
    return request.then(response => response.data)
}

const create = (newObject) => {
    const request = axios.post(baseUrl, newObject)
    return request.then(response => response.data)
}

const update = (newObject, id) => {
    const request = axios.put(`${baseUrl}/${id}`, newObject)
    return request.then(response => response.data)
}

const remove = (id) => {
    const request = axios.delete(`${baseUrl}/${id}`)
    return request.then(response => response.data)
}

const contactService = { getAll, create,  update, remove }

export default contactService
Enter fullscreen mode Exit fullscreen mode

Our module returns an object with four functions that directly return the response data by the axios methods.

"Wait, where did remove come from? and why not call it 'delete'?"

Well, if you've been paying attention since the beginning, I mentioned we'd go through GET, POST, PUT, and DELETE requests. I intend to keep that promise. delete is a reserved JavaScript word so just don't.
Captain America Just Don't gif

Let's take it step-by-step:

const getAll = () => {
    const request = axios.get(baseUrl)
    return request.then(response => response.data)
}
Enter fullscreen mode Exit fullscreen mode

Our modified getAll function still returns a promise, as the then method of a promise also returns a promise. Once we define the parameter of the then method to return response.data, we've managed for our getAll function to work. Once the HTTP request is successful, the promise returns the data as a response from the backend module.

We can now import our contactService module into our React App.

import contactService from './services/contacts';
Enter fullscreen mode Exit fullscreen mode

Our functions can be used directly from the imported contactService module.

import React, { useState, useEffect } from 'react';
import contactService from './services/contacts';

const App = () => {
// ...

const hook = () => {
    contactService
    .getAll()
    .then(initialContacts => {
      setPeople(initialContacts)
    })
  }
  useEffect(hook, [])

const addContact = (e) => {
    e.preventDefault()

    const nameObj = {
      name: newName,
      number: newNumber
    }

    contactService
    .create(nameObj)
    .then(returnedContact => {
     setPeople(people.concat(returnedContact))
    })
    setNewName('')
    setNewNumber('')
  }

const handleSubmit = (e) => {
    e.preventDefault()

    const exists = people.find(person => person.name === newName)

    if(exists) {
      const person = people.find(p => p.name === newName)
      const confirmChange = window.confirm(`${newName} already exists. Replace old number with a new one?`)
      if(confirmChange) {
      const id = person.id
      const updatedPerson = {...person, number: newNumber}

      contactService
      .update(updatedPerson, id)
      .then(returnedContact => {
      setPeople(people.map(p => p.id !== id ? p : returnedContact))
      })
      } else {
        setPeople(people)
      }
    } else {
      addContact(e)
    } 
    setNewName('')
    setNewNumber('')
  }


// ...
}

export default App
Enter fullscreen mode Exit fullscreen mode

Looking cleaner and leaner already!

We're now ready to implement our deleteContact function.

const App = () => {
// ...
const deleteContact = id => {
    const person = people.find(p => p.id === id)
    const confirmDelete = window.confirm(`Delete ${person.name}?`)
if(confirmDelete) {
    contactService
    .remove(id)
    .then(() => {
        setPeople(people.filter(p => p.id !== id))
    })
     // error handling that will just print to console for now.
     .catch(error => {
      console.log(error)
    })
    setNewName('')
    setNewNumber('')
  }
}

// ...
}
export default App
Enter fullscreen mode Exit fullscreen mode

Pretty straightforward stuff. Once our deleteContact function is called, we set a person variable to match the id passed. Then if confirmDelete is true we run our remove function passed from our contactService module. Next, we chain .then() which attaches a callback that is invoked when the promise is settled. Inside this callback, we filter out contacts that don't match the id thus causing a re-render which updates our app accordingly. Lastly a .catch() is chained for any error handling (for now we'll just log the error to console, I'll cover error handling in another post).

SpongeBob tired

Take a breather, you've earned it!

That does it for our journey through axios HTTP requests. I hope you had as much fun as I had following along! In the spirit of keeping things simple, I omitted adding other React components as well as the passing down of props. I wanted to mainly focus on the backend logic and functionality while using axios. The beauty of this is that one could easily pass down the functions we wrote as event handlers to our props.

Resources

💖 💪 🙅 🚩
crrojas88
Rodrigo Rojas

Posted on June 14, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related