Using json-server to create a mock back-end for front-end development
Tags: react, javascript, frontend, webdev
Published: 2023-10-26 15:49:15

Front-end development entails retrieving data from external sources, such as an API, and displaying it on the user interface.
During development, front-end developers are often in a situation where they need to interact with a back-end API, but it is not fully implemented, or readily available. In a situation like this, a mock back-end is extremely usefully.

In this article, we'll consider a tool used for creating mock API called 'JSON server'. We'll build a phonebook application, where we'll perform basic crud operations on the mock server, such as:
- Creating new contacts.
- Fetching contacts from the phonebook.
- Deleting contacts.

## Prerequisites
- Knowledge of JavaScript and React.
- Knowledge of basic operations done using a terminal
- A web browser.
- Node.JS installed on your computer.
- A text editor (preferably VS Code).

## A brief overview of json-server
**JavaScript Object Notation(JSON)** is a text-based format used for structuring data (based on JavaScript object syntax) and exchanging data in web applications. **JSON-Server** is a tool that creates a mock back-end. It simulates a REST API, with little to no coding in less than a minute.

## Why use json-server 
Here are several using for using json-server:
- Rapid Development: json-server allows you to create a mock back-end quickly. You don't need to set up a full-fledged back-end server or database, making it ideal for prototyping and development in the early stages of a project.
- Prototyping: It's an excellent choice for rapidly prototyping applications. You can define your data structure and API endpoints without worrying about setting up a full back-end system.
- Isolated Development: It allows you to work on different components of an application in isolation. Front-end and back-end development can progress independently, provided they adhere to the defined API contract.

## Create a phonebook application using json-server and React
This section shows how you can practically use json-server. In this section, you will build a phonebook application. The back-end will be mocked using json-server, and the front-end will be created using React. Here's a look at what we'll be building.


![Phonebook Application](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aib2sk3aiygibax4lhf1.png)


### Create React application
Firstly, create a React application. You can bootstrap a React application using either Vite or Create React App. To create a React application using Vite and Node Package Manager(NPM):
1. Type the following command into a terminal `npm create vite@latest`.
2. Choose an appropriate project name, e.g phonebook.
3. Choose React as the framework.
4. Select JavaScript as the variant.

As shown on the terminal after successfully bootstraping using Vite:
1. Navigate to the project folder, using `cd phonebook`.
2. Install the dependencies using the command `npm install`

This tutorial will be using React-Bootstrap, and Bootstrap for styling. Although, you can use any styling framework of your preference. To install React-Bootstrap, type the following command into the terminal: `npm install react-bootstrap bootstrap`

Axios will be used for handling HTTP requests to the server. Install axios using the following command: `npm install axios`

### Setting up json-server
You can install json-server globally using the following command: `npm install -g json-server`.  A global installation is not needed, so to install json-server as a development dependency, use the following command `npm install --save-dev json-server`

At the root of the project directory, create a `db.json` file with the following data:
``` javascript
{
  "contacts": [
    {
      "name": "Emma Smith",
      "number": "555-123-4567",
      "id": 1
    },
    {
      "name": "Liam Johnson",
      "number": "555-234-5678",
      "id": 2
    },
    {
      "name": "Olivia Brown",
      "number": "555-345-6789",
      "id": 3
    },
    {
      "name": "Noah Davis",
      "number": "555-456-7890",
      "id": 4
    },
    {
      "name": "Ava Wilson",
      "number": "555-567-8901",
      "id": 5
    }
  ]
}
```

Start the server using the following command: `json-server --watch db.json`. By default, the server runs on port 3000. 
We can define an alternate port using the `--port` flag : `json-server --port 3001 --watch db.json`
The `--watch` flag looks for a file changes made to the `db.json` file.

Save the command for starting the server as a script in `package.json`:
``` javascript
{
	//...
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint . --ext js,jsx --report-unused-disable-directives --max-warnings 0",
    "preview": "vite preview",
    "server": "json-server -p3001 --watch db.json"
  },
 }
```
You can now start the server at the root of the project directory with the following command: `npm run server`
If you navigate to the address `http://localhost:3001/contacts
` on the browser, you will see the data written to the `db.json` file displayed in JSON format.


![Server data on browser](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4pa45acrcbr4w82d1xp.png)

JSON Server automatically saves changes made by PUT, POST, PATCH, or DELETE request to the `db.json` file.

JSON Server defines routes based on the data provided in the `db.json` file. Here are the default routes, based on the contents of the phonebook application:
- GET   `/contacts`
- GET   `/contacts/1`
- POST   `/contacts`
- PUT    `/contacts/1`
- PATCH  `/contacts/1`
- DELETE `/posts/1`

### Building the application
Remove the default `App.css` and the `index.css` files created by Vite from the `src` directory. 

#### Create services folder
Extract the code for interacting with the external API into a separate folder called `services`. This helps in cleaning up the code. In the `src`  directory, create the `services` folder, add a file there called `contact.js`, with the following content:

``` javascript
import axios from 'axios'
const baseUrl = 'http://localhost:3001/contacts'

const getAll = async () => {
  const response = await axios.get(baseUrl)
  return response.data
}

const addContact = async (contact) => {
  const response = await axios.post(baseUrl, contact)
  return response.data
}

const deleteContact = async (id) => {
  const response = await axios.delete(`${baseUrl}/${id}`)
  return response.data
}

export default { getAll, addContact, deleteContact }
```

### Manage state using useReducer
This tutorial makes use of React's inbuilt `useReducer` hook, and the Context API to access and manage the state of the application globally.
To do this:
1. Create a file at the root of the project directory called `ContactsContext.jsx`.  
2. In the `ContactsContext.js`, create the reducer function that will be responsible for handling state changes. 
3. Create the context `ContactsContext` using React's `createContext`  hook.
4. Create and export the context provider, `ContactsContext.Provider`.

``` react
import { createContext, useReducer } from 'react'

const contactsReducer = (state, action) => {
  switch (action.type) {
  case 'SET_CONTACTS':
    return action.payload
  case 'ADD_CONTACT':
    return [...state, action.payload]
  case 'REMOVE_CONTACT':
    return state.filter(contact => contact.id !== action.payload.id)
  default:
    return state
  }
}

const ContactsContext = createContext()

export const ContactsContextProvider = (props) => {
  const [contacts, contactsDispatch] = useReducer(contactsReducer, [])

  return (
    <ContactsContext.Provider value={[contacts, contactsDispatch]}>
      {props.children}
    </ContactsContext.Provider>
  )
}

export default ContactsContext
```

In `main.jsx` file, wrap the  `Contacts.Context.Provider` around the `App` component. 
``` react
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import { ContactsContextProvider } from './ContactsContext.jsx'

import 'bootstrap/dist/css/bootstrap.min.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <ContactsContextProvider>
      <App />
    </ContactsContextProvider>
  </React.StrictMode>
)
```

#### Fetching and rendering contacts, and deleting contacts 
An important part of this application is fetching contacts from the server, and displaying them on the browser. To do this, create a folder in the `src` directory called `components`. In the `components` folder create the component '`Contacts.jsx`:
``` react
import { useContext } from 'react'
import contactServices from '../services/contacts'
import ContactsContext from '../ContactsContext'

const Contacts = () => {
  const [contacts, dispatch] = useContext(ContactsContext)

  const deleteContact = async (id) => {
    const response = await contactServices.deleteContact(id)
    dispatch({
      type: 'REMOVE_CONTACT',
      payload: { id },
    })
  }

  return (
    <div className="my-4">
      <table className="table table-striped table-bordered">
        <thead>
          <tr>
            <th scope="col">Contact Name</th>
            <th scope="col">Contact Number</th>
            <th scope="col"></th>
          </tr>
        </thead>
        <tbody className="table-group-divider">
          {contacts.map((contact) => (
            <tr key={contact.id}>
              <td>{contact.name}</td>
              <td>{contact.number}</td>
              <td>
                <button
                  type="button"
                  className="btn btn-danger"
                  onClick={() => deleteContact(contact.id)}
                >
                  Delete
                </button>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}

export default Contacts
```

#### Creating new contacts
Create a `ContactForm.jsx` file in the already created `components` directory. This component is responsible for creating new contacts.
``` javascript
import { useContext, useState } from 'react'
import { Button, Form, Modal } from 'react-bootstrap'
import contactServices from '../services/contacts'
import ContactsContext from '../ContactsContext'

const ContactForm = ({ show, handleClose }) => {
  const [contacts, dispatch] = useContext(ContactsContext)

  const [name, setName] = useState('')
  const [number, setNumber] = useState('')

  const addContact = async (event) => {
    event.preventDefault()
    const response = await contactServices.addContact({ name, number })
    dispatch({
      type: 'ADD_CONTACT',
      payload: response,
    })
    setName('')
    setNumber('')
    handleClose()
  }

  const handleNameChange = (event) => setName(event.target.value)
  const handleNumberChange = (event) => setNumber(event.target.value)

  return (
    <Modal show={show} onHide={handleClose}>
      <Modal.Header closeButton>
        <Modal.Title>Add Contact</Modal.Title>
      </Modal.Header>
      <Modal.Body>
        <Form onSubmit={addContact}>
          <Form.Group className="mb-3" controlId="formBasicName">
            <Form.Label>Name</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter Contact Name"
              value={name}
              onChange={handleNameChange}
            />
          </Form.Group>

          <Form.Group className="mb-3" controlId="formBasicNumber">
            <Form.Label>Number</Form.Label>
            <Form.Control
              type="text"
              placeholder="Enter Contact Number"
              value={number}
              onChange={handleNumberChange}
            />
          </Form.Group>

          <Button variant="primary" type="submit">
            Submit
          </Button>
        </Form>
      </Modal.Body>
    </Modal>
  )
}

export default ContactForm

```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9c5bfybx0ruffvkwwn57.png)

### Bringing it all together 
In the `App.jsx` component:

``` react
import { useContext, useEffect, useState } from 'react'
import contactServices from './services/contacts'
import ContactsContext from './ContactsContext'

import ContactForm from './components/ContactForm'
import Contacts from './components/Contacts'

const App = () => {
  const [contacts, dispatch] = useContext(ContactsContext)

  const [showContactForm, setShowContactForm] = useState(false)
  const handleCloseContactForm = () => setShowContactForm(false)
  const handleShowContactForm = () => setShowContactForm(true)

  useEffect(() => {
    const getContacts = async () => {
      const response = await contactServices.getAll()
      dispatch({
        type: 'SET_CONTACTS',
        payload: response,
      })
    }
    getContacts()
  }, [dispatch])


  return (
    <>
      <ContactForm
        handleClose={handleCloseContactForm}
        show={showContactForm}
      />

      <nav className="navbar bg-dark">
        <div className="container">
          <a className="navbar-brand text-light" href="#">
            PhoneBook
          </a>
        </div>
      </nav>
      <div className="container py-4">
        <button
          type="button"
          className="btn btn-primary"
          onClick={handleShowContactForm}
        >
          Add New
        </button>
        <Contacts />
      </div>
    </>
  )
}

export default App
```

## Conclusion
This article provided an introduction into json-server, and its importance in front-end web development. 

The tutorial showed you how to use json-server to create a mock back-end by building a phonebook application.

Check out the full code used for this tutorial [here](https://github.com/michaelikoko/Phonebook)

## References
- [JSON Server](https://github.com/typicode/json-server)
-  [Fullstack open](https://fullstackopen.com/en/part2/getting_data_from_server#npm)