DEV Community

Cover image for Full-Stack React & Node.js - HTTP POST
Dave
Dave

Posted on

Full-Stack React & Node.js - HTTP POST

Now we're going to POST data to our server from the client.

Previously we've used HTTP GET requests which are for getting data. To add data we use HTTP POST.

First we need to make a few small changes to our node-server.

Edit note.controller.js to:

const note = {
  id: 1,
  title: 'A Note',
  content: 'Lorem ipsum dolor sit amet',
  author: 'neohed',
  lang: 'en',
  isLive: true,
  category: '',
}

async function getNote(req, res) {
  res.json({ note });
}

async function postNote(req, res) {
  const {body} = req;
  const {id, title, content, author, lang, isLive, category} = body;

  console.log('Server received data:');
  console.log({id, title, content, author, lang, isLive, category})

  res
    .status(200)
    .json({
      message: 'Ok'
    })
}

module.exports = {
  getNote,
  postNote
}
Enter fullscreen mode Exit fullscreen mode

We've added a new function, postNote. As we don't yet have a DB we simply log out the data to prove we've received it.

Next, edit routes/index.js to:

const express = require('express');
const noteRouter = express.Router();
const noteController = require('../controllers/note.controller');

noteRouter.get('', noteController.getNote);
noteRouter.post('', noteController.postNote);

const routes = app => {
  app.use('/note', noteRouter);
};

module.exports = routes
Enter fullscreen mode Exit fullscreen mode

Notice that we mounted our new controller method noteController.postNote to the same endpoint as getNote. Both are accessed from the same URL /note

This is RESTful architecture. It stands for REpresentational State Transfer. The key point is that the URL endpoint, or segment, we use represents the entity, and the HTTP verb, e.g., GET or POST, represents the action! The object entity is note so the URL endpoint is also note for all operations. To distinguish between different operations such as GET, POST and later DELETE, and others, we use the HTTP verbs which we send in our fetch request.

We use specific express router functions .get() and .post() and later .delete(), so that express knows, that when an HTTP GET request for the /note URL endpoint is received, it should be routed to .getNote and when an HTTP POST is received it should be routed to .postNote()

Following a RESTful architecture means your server API will be simple and clean. Using the combination of URL segments and HTTP verbs to architect the conversation between client and server allows for a simple and expressive representation.

Next we need to update our react-client

First a little bit of refactoring. Create a new file in react-client called strings.js and paste in this code:

const isNullOrUndefined = prop => prop === null
  || prop === undefined;
const isEmptyString = prop => isNullOrUndefined(prop)
  || prop === '';
const capitalize = word =>
  word.charAt(0).toUpperCase() +
  word.slice(1).toLowerCase();

function titleFromName(name) {
  if (isEmptyString(name)) {
    return '';
  }

  return name.split(/(?=[A-Z])|\s/).map(s => capitalize(s)).join(' ')
}

export {
  isNullOrUndefined,
  isEmptyString,
  capitalize,
  titleFromName,
}
Enter fullscreen mode Exit fullscreen mode

Next, edit Form.js to:

import React from 'react';
import InputLabel from "./InputLabel";
import {isEmptyString, titleFromName} from "./strings";
import './form.css'

const Form = ({entity, onSubmitHandler}) => {
  return (
    <form onSubmit={e => {
      const form = e.target;
      const newEntity = Object.values(form).reduce((obj, field) => {
        if (!isEmptyString(field.name)) {
          obj[field.name] = field.value
        }

        return obj
      }, {})

      onSubmitHandler(newEntity);

      e.stopPropagation();
      e.preventDefault()
    }}>
      {
        Object.entries(entity).map(([entityKey, entityValue]) => {
          if (entityKey === "id") {
            return <input
              type="hidden"
              name="id"
              key="id"
              value={entityValue}
            />
          } else {
            return <InputLabel
              id={entityKey}
              key={entityKey}
              label={titleFromName(entityKey)}
              type={
                typeof entityValue === "boolean"
                  ? "checkbox"
                  : "text"
              }
              value={entityValue}
            />
          }
        })
      }
      <button
        type="submit"
      >
        Submit
      </button>
    </form>
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

The main change, other than removing the string utility functions, is to add a form onSubmit event handler that grabs all form fields and adds the name & value pairs as properties and values in an object, then passes that object to an event handler parameter.

Next edit AddEditNote.js to implement this new onSubmitHandler parameter.

Paste this code into AddEditNote.js:

import React, {useState, useEffect} from 'react';
import RenderData from "./RenderData";
import Form from './Form';

const AddEditNote = () => {
  const [note, setNote] = useState({});

  useEffect( () => {
    const abortController = new AbortController();

    async function fetchData() {
      console.log('Calling fetch...')
      try {
        const response = await fetch('http://localhost:4011/note', {
          signal: abortController.signal,
        });

        if (response.ok) {
          console.log('Response received from server and is ok!')
          const {note} = await response.json();

          if (abortController.signal.aborted) {
            console.log('Abort detected, exiting!')
            return;
          }

          setNote(note)
        }
      } catch(e) {
        console.log(e)
      }
    }

    fetchData()

    return () => {
      console.log('Aborting GET request.')
      abortController.abort();
    }
  }, [])

  return (
    <div>
      <RenderData
        data={note}
      />
      <Form
        entity={note}
        onSubmitHandler={async newNote => {
          const response = await fetch('http://localhost:4011/note', {
            method: 'POST',
            body: JSON.stringify(newNote),
            headers: {
              'Content-Type': 'application/json'
            }
          });

          if (response.ok) {
            const res = await response.json()
            console.log(res)
          }
        }}
      />
    </div>
  );
};

export default AddEditNote
Enter fullscreen mode Exit fullscreen mode

If you run this code, navigate to the form, edit the values then click submit and take a look at the server console, you should see the values you typed into the form have been posted back to the server and extracted from the HTTP message.

Next we will add a database...

Code repo: Github Repository

Discussion (0)