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
}
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
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,
}
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;
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
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
Top comments (0)