Full-Stack React & Node.js - HTTP POST
Tags: react, node, javascript, webdev
Published: 2022-06-28 16:31:13

---
series: Simply Learn Full-Stack React & Node.js
---

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:

```javascript
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
}
```

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:

```javascript
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
```

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:

```javascript
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,
}
```

Next, edit **Form.js** to:

```jsx
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;
```

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**:

```jsx
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
```

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](https://github.com/neohed/node-react-stack)