Built at: 2024-10-16T09:55:25.150Z Skip to content

part3a

hello world

command version

Terminal window
pnpm init

add “start” in scripts section

// package.json
"start": "node index.js",

add index.js

index.js
console.log("hello world");
Terminal window
node index.js

or

Terminal window
pnpm start

Simple web server

index.js
const http = require("http");
const app = http.createServer((request, response) => {
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello World");
});
const PORT = 3001;
app.listen(PORT);
console.log(`Server running on port ${PORT}`);
Terminal window
pnpm start

check http://localhost:3001 and http://localhost:3001/foo/bar

response json
// index.js
const http = require("http");
let notes = [
{
id: "1",
content: "HTML is easy",
important: true,
},
{
id: "2",
content: "Browser can execute only JavaScript",
important: false,
},
{
id: "3",
content: "GET and POST are the most important methods of HTTP protocol",
important: true,
},
];
const app = http.createServer((request, response) => {
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify(notes));
});
const PORT = 3001;
app.listen(PORT);
console.log(`Server running on port ${PORT}`);

check http://localhost:3001 and http://localhost:3001/notes

Express

Terminal window
pnpm i express

Web and Express

index.js
const express = require("express");
const app = express();
let notes = [
{
id: "1",
content: "HTML is easy",
important: true,
},
{
id: "2",
content: "Browser can execute only JavaScript",
important: false,
},
{
id: "3",
content: "GET and POST are the most important methods of HTTP protocol",
important: true,
},
];
app.get("/", (request, response) => {
response.send("<h1>Hello World!</h1>");
});
app.get("/api/notes", (request, response) => {
response.json(notes);
});
const PORT = 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
Terminal window
pnpm start

check http://localhost:3001/ and http://localhost:3001/api/notes

nodemon

Terminal window
pnpm i -D nodemon

add scripts

// package.json
"dev": "nodemon index.js",

Fetching a single resource

app.get("/api/notes/:id", (request, response) => {
const id = request.params.id;
const note = notes.find((note) => note.id === id);
if (note) {
response.json(note);
} else {
response.status(404).end();
}
});

Deleting resources

app.delete("/api/notes/:id", (request, response) => {
const id = request.params.id;
notes = notes.filter((note) => note.id !== id);
response.status(204).end();
});

VSCode REST client

Add new folder “requests” at root.

Add new file extend name .rest in it.

get_all_notes.rest
GET http://localhost:3001/api/notes
###
POST http://localhost:3001/api/notes/ HTTP/1.1
content-type: application/json
{
"name": "sample",
"time": "Wed, 21 Oct 2015 18:27:50 GMT"
}

Click on the “Send Request” button while viewing this file, it will imply the request and show the response at right side.

Receiving data

index.js
const express = require("express");
const app = express();
app.use(express.json());
//...
app.post("/api/notes", (request, response) => {
const maxId =
notes.length > 0 ? Math.max(...notes.map((n) => Number(n.id))) : 0;
const note = request.body;
note.id = String(maxId + 1);
notes = notes.concat(note);
response.json(note);
});

Response 400 on empty content

const generateId = () => {
const maxId =
notes.length > 0 ? Math.max(...notes.map((n) => Number(n.id))) : 0;
return String(maxId + 1);
};
app.post("/api/notes", (request, response) => {
const body = request.body;
if (!body.content) {
return response.status(400).json({
error: "content missing",
});
}
const note = {
content: body.content,
important: Boolean(body.important) || false,
id: generateId(),
};
notes = notes.concat(note);
response.json(note);
});

Exercises 3.1 - 3.6

Setup a new repo.

3.1 Phonebook backend step 1

http://localhost:3001/api/persons

[
{
id: "1",
name: "Arto Hellas",
number: "040-123456",
},
{
id: "2",
name: "Ada Lovelace",
number: "39-44-5323523",
},
{
id: "3",
name: "Dan Abramov",
number: "12-43-234345",
},
{
id: "4",
name: "Mary Poppendieck",
number: "39-23-6423122",
},
];

3.2 Phonebook backend step 2

http://localhost:3001/info

The page has to show the time that the request was received and how many entries are in the phonebook at the time of processing the request.

3.3 Phonebook backend step 3

Get single person

http://localhost:3001/api/persons/5

3.4 Phonebook backend Step 4

Delete single person

3.5 Phonebook backend step 5

Create person

Generate a new id for the phonebook entry with the Math.random function. Use a big enough range for your random values so that the likelihood of creating duplicate ids is small.

3.6 Phonebook backend step 6

Error handling for creating new entries.

The request is not allowed to succeed, if:

  • The name or number is missing
  • The name already exists in the phonebook
{ "error": "name must be unique" }

My solutions

My solutions:
(Please complete your own solutions before click here.)

3.1 /api/persons

Terminal window
cd exercises
makedir part3
cd part3
mkdir phonebook
cd phonebook
pnpm init
code .
add scripts:
"start": "node index.js",
add index.js, content: console.log("hello world")
pnpm start
pnpm i nodemon
pnpm i express
add scripts:
"dev": "nodemon index.js",
pnpm dev
index.js
const express = require("express");
const app = express();
app.use(express.json());
let persons = [
{
id: "1",
name: "Arto Hellas",
number: "040-123456",
},
{
id: "2",
name: "Ada Lovelace",
number: "39-44-5323523",
},
{
id: "3",
name: "Dan Abramov",
number: "12-43-234345",
},
{
id: "4",
name: "Mary Poppendieck",
number: "39-23-6423122",
},
];
app.get("/api/persons", (request, response) => {
response.json(persons);
});
const PORT = 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

add requests/get_all_persons.rest

// get_all_persons.rest
GET http://localhost:3001/api/persons

3.2 /info

pnpm i axios
index.js
const axios = require("axios");
const express = require("express");
const app = express();
app.use(express.json());
let persons = [
{
id: "1",
name: "Arto Hellas",
number: "040-123456",
},
{
id: "2",
name: "Ada Lovelace",
number: "39-44-5323523",
},
{
id: "3",
name: "Dan Abramov",
number: "12-43-234345",
},
{
id: "4",
name: "Mary Poppendieck",
number: "39-23-6423122",
},
];
app.get("/api/persons", (request, response) => {
response.json(persons);
});
app.get("/info", (request, response) => {
let respPersons;
axios.get("http://localhost:3001/api/persons").then((resp) => {
// console.log(resp)
respPersons = resp.data;
// console.log(respPersons)
response.send(`
Phonebook has info for ${respPersons.length} ${
respPersons.length === 1 ? "person" : "people"
} <br />
${new Date().toString()}
`);
});
});
const PORT = 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});
get_all_persons.rest
GET http://localhost:3001/api/persons
###
GET http://localhost:3001/info

3.3 Get single person
3.4 Delete single person
3.5 Post one person

index.js
const axios = require("axios");
const express = require("express");
const app = express();
app.use(express.json());
let persons = [
{
id: "1",
name: "Arto Hellas",
number: "040-123456",
},
{
id: "2",
name: "Ada Lovelace",
number: "39-44-5323523",
},
{
id: "3",
name: "Dan Abramov",
number: "12-43-234345",
},
{
id: "4",
name: "Mary Poppendieck",
number: "39-23-6423122",
},
];
app.get("/api/persons", (request, response) => {
response.json(persons);
});
app.get("/info", (request, response) => {
let respPersons;
axios.get("http://localhost:3001/api/persons").then((resp) => {
// console.log(resp)
respPersons = resp.data;
// console.log(respPersons)
response.send(`
Phonebook has info for ${respPersons.length} ${
respPersons.length === 1 ? "person" : "people"
} <br />
${new Date().toString()}
`);
});
});
app.get("/api/persons/:id", (request, response) => {
const id = request.params.id;
const person = persons.find((person) => person.id === id);
if (person) {
response.json(person);
} else {
response.status(404).end();
}
});
app.delete("/api/persons/:id", (request, response) => {
const id = request.params.id;
persons = persons.filter((person) => person.id !== id);
response.status(204).end();
});
const generateId = () => {
const maxId =
persons.length > 0 ? Math.max(...persons.map((p) => Number(p.id))) : 0;
return String(maxId + 1);
};
app.post("/api/persons", (request, response) => {
const body = request.body;
if (!body.name || !body.number) {
return response.status(400).json({
error: "person name or number missing",
});
}
const person = {
name: body.name,
number: body.number,
id: generateId(),
};
persons = persons.concat(person);
response.json(person);
});
const PORT = 3001;
app.listen(PORT, () => {
console.log(`Server running on port ${PORT}`);
});

3.6 error handling

  • name and number can’t be missing
  • name must be unique
Terminal window
pnpm i lodash
app.post("/api/persons", (request, response) => {
const body = request.body;
if (!body.name || !body.number) {
return response.status(400).json({
error: "person name or number missing",
});
}
const personsNameArray = persons.map((p) => p.name);
if (_.includes(personsNameArray, body.name)) {
return response.status(400).json({
error: "name must be unique",
});
}
const person = {
name: body.name,
number: body.number,
id: generateId(),
};
persons = persons.concat(person);
response.json(person);
});

Middleware

Middleware running position(app.use(…)) is important.

const requestLogger = (request, response, next) => {
console.log("Method:", request.method);
console.log("Path: ", request.path);
console.log("Body: ", request.body);
console.log("---");
next();
};
app.use(requestLogger);
const unknownEndpoint = (request, response) => {
response.status(404).send({ error: "unknown endpoint" });
};
app.use(unknownEndpoint);

Exercises 3.7 - 3.8

3.7 Phonebook backend step 7

Add the morgan middleware to your application for logging. Configure it to log messages to your console based on the tiny configuration.

3.8* Phonebook backend step 8

Configure morgan so that it also shows the data sent in HTTP POST requests:

POST /api/persons 200 61 - 4.896 ms {"name":"Liisa Marttinen","number":"040-243563"}

This exercise can be completed in a few different ways. One of the possible solutions utilizes these two techniques:

  • creating new tokens
  • JSON.stringify

My solutions

My solutions:
(Please complete your own solutions before click here.)

3.7 use morgan middleware, tiny configuration

Terminal window
pnpm i morgan
index.js
const morgan = require("morgan");
app.use(morgan("tiny"));

3.8* add post request body to the morgan log

index.js
morgan.token('postBody', function getPostBody(req) {
// console.log(req.method)
// console.log(JSON.stringify(req.body) === JSON.stringify({}))
// if (JSON.stringify(req.body) !== JSON.stringify({})) {
if (req.method.toLowerCase() === "post".toLowerCase()) {
return JSON.stringify(req.body)
}
return null
})
app.use(express.json());
// app.use(morgan("tiny"))
app.use(morgan(':method :url :status :res[content-length] - :response-time ms :postBody'))