Skip to content

Latest commit

 

History

History
 
 

12-api-lib

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Step 12 - API lib

Now that we've built out all of the UI functionality, the App component is doing way too much. Right now it makes API calls and has lots of logic of how to go from one state to the next. The goal of this step is to consolidate all of the API calls from the App component into a single file. This will be the first step in lightening the App to only deal with component-related tasks. We'll tackle the rest in Step 13.

As always, if you run into trouble with the tasks or exercises, you can take a peek at the final source code.

Restart Setup

If you didn't successfully complete the previous step, you can jump right in by copying the step and installing the dependencies.

Ensure you're in the root folder of the repo:

cd react-workshop

Remove the existing workshop directory if you had previously started elsewhere:

rm -rf workshop

Copy the previous step as a starting point:

cp -r 11-email-form-modal workshop

Change into the workshop directory:

cd workshop

Install all of the dependencies (yarn is preferred):

# Yarn
yarn

# ...or NPM
npm install

Start API server (running at http://localhost:9090/):

# Yarn
yarn run start:api

# ...or NPM
npm run start:api

In a separate terminal window/tab, making sure you're still in the workshop directory, start the app:

# Yarn
yarn start

# ...or NPM
npm start

After the app is initially built, a new browser window should open up at http://localhost:3000/, and you should be able to continue on with the tasks below.

Tasks

In App, take the code making the fetch request in _getUpdateEmails() and move into a new src/api/index.js file. Put the code in a exported function called getEmails():

export const getEmails = () =>
  // Make a GET request
  fetch('//localhost:9090/emails')
    .then(res => res.json())
    .catch(ex => console.error(ex));

Back in App, import the getEmails() function and use it in _getUpdateEmails():

// other imports

import {getEmails} from './api';

// helper components

export default class App extends PureComponent {
  // prop types & default props

  // initialize state

  // lifecycle methods

  _getUpdateEmails() {
    return getEmails()
      .then(emails => this.setState({emails}));
  }

  // other helper methods

  // render()
}

Move the fetch logic for adding a new email out of _handleFormSubmit() into a new addEmail() API lib function:

export const addEmail = email =>
  // Make a JSON POST with the new email
  fetch('//localhost:9090/emails', {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(email)
  })
    .then(res => res.json())
    .catch(ex => console.error(ex));

The API lib only has two functions and already has a lot of repetition. Factor out the fetch URL into a shared const and create a _fetchJSON helper utility:

const API_BASE_URL = '//localhost:9090/emails';

const _fetchJson = (url, options) =>
  fetch(url, options)
    .then(res => res.json())
    .catch(ex => console.error(ex));

export const addEmail = email =>
  // Make a JSON POST with the new email
  _fetchJson(API_BASE_URL, {
    method: 'POST',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(email)
  });

export const getEmails = () =>
  // Make a GET request
  _fetchJson(API_BASE_URL);

Now in App use addEmail in _handleFormSubmit():

// other imports

import {addEmail, getEmails} from './api';

// helper components

export default class App extends PureComponent {
  // prop types & default props

  // initialize state

  // lifecycle methods

  _handleFormSubmit(newEmail) {
    // Make a JSON POST with the new email
    addEmail(newEmail).then(({success}) => {
      if (success) {
        this.setState(({emails}) => {
          // if the email was successfully updated, we have to make
          // a request to get the new list of emails, but we'll have
          // to wait for the response of that request, so let's add to
          // our state immediately and then later when the response
          // comes back, the server-side list will update. This is mainly
          // here to demonstrate immutable updating of data structures

          // Create a full email info by spreading in `id`, `date` & `unread`
          // Then spread to front of emails state (since it's the newest)
          let newEmails = [
            {
              ...newEmail,
              id: Date.now(),
              date: `${new Date()}`,
              unread: true
            },
            ...emails
          ];

          // Set state with new updated emails list
          return {
            emails: newEmails,
            showForm: false
          };
        });
      } else {
        throw new Error('Unable to send email!');
      }
    });
  }

  // other helper methods

  // render()
}

Exercises

  • Factor out the remaining fetch calls in App into the helper API lib

Next

Go to Step 13 - Action-Reducers.

Resources

Questions

Got questions? Need further clarification? Feel free to post a question in Ben Ilegbodu's AMA!