4
\$\begingroup\$

I build a RESTful CRUD API with Node.js and Express. This application allows, for example, to create a table on the client side with the ability to add, update and remove data by ID. I generate an array of random data for the availability of data when you start working on the client side with the table. I will be grateful for tips on improving the style.

const express = require('express')
const bodyParser = require('body-parser')
const crypto = require("crypto");
const cors = require('cors')
const getId = () => crypto.randomBytes(16).toString("hex");
const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min)) + min;
const nameList = ['Andrew', 'John', 'Sebastian', 'Owen', 'Luke', 'Anthony', 'Dylan']
const cityList = ['Riga', 'Berlin', 'Paris', 'Tokyo', 'London', 'Milan', 'Madrid']
const colorList = ['red', 'blue', 'green']
const getRandomStr = (str) => (str[getRandomInt(0, str.length)])
const app = express()
const names = [
 { id: getId(), 
 name: 'Li', 
 city: 'Tokyo', 
 color: 'blue', 
 answers: '10', 
 reputation: '1725' }
]
const generateNames = () => {
 for (let i=0; i<50; i++){
 const newId = getId()
 const newName = getRandomStr(nameList) 
 const newCity = getRandomStr(cityList)
 const newColor = getRandomStr(colorList)
 const newAnswers = getRandomInt(10, 20).toString()
 const newReputation = getRandomInt(1500, 2000).toString()
 names.push({ id: newId, name: newName, city: newCity, 
 color: newColor, answers: newAnswers, reputation: newReputation })
 }
}
generateNames()
app.use(bodyParser.json())
app.use(cors())
app.get('/names', (req, res) => {
 res.json(names)
})
app.post('/names', (req, res) => {
 const newId = getId() 
 const newName = req.body.name 
 const newCity = req.body.city
 const newColor = req.body.color
 const newAnswers = req.body.answers
 const newReputation = req.body.reputation
 names.push({ id: newId, name: newName, city: newCity, 
 color: newColor, answers: newAnswers, reputation: newReputation })
 res
 .status(201) 
 .json({ id: newId }) 
})
app.put('/names', (req, res) => {
 const { id } = req.body
 const indexToEdit = names.findIndex(obj => obj.id === id )
 names[indexToEdit].name = req.body.name
 names[indexToEdit].city = req.body.city
 names[indexToEdit].color = req.body.color
 names[indexToEdit].answers = req.body.answers
 names[indexToEdit].reputation = req.body.reputation
 const editName = names[indexToEdit].name
 const editCity = names[indexToEdit].city
 const editColor = names[indexToEdit].color
 const editAnswers = names[indexToEdit].answers
 const editReputation = names[indexToEdit].reputation
 res
 .status(200)
 .json({ name: editName, city: editCity, 
 color: editColor, answers: editAnswers, reputation: editReputation})
})
app.delete('/names', (req, res) => {
 const { id } = req.body 
 const indexToRemove = names.findIndex(obj => obj.id === id )
 names.splice(indexToRemove, 1) 
 res
 .status(200)
 .json({ status: 'success'})
})
app.listen(3000, () => {
 console.log('listening on 3000')
})
asked Apr 18, 2018 at 19:04
\$\endgroup\$

1 Answer 1

5
\$\begingroup\$

I know you are generating data for the sake of completion but it does complicate things on what aspect of the code you'd like to focus on. But here are a couple thoughts.

With Express, I often like to treat the routes as controllers in an MVC pattern. So any fetching of data and mutating data, I would create at least a model per resource to encapsulate that part of the code. So the interface may look something like the below:

app.get('/names', async (req, res) => {
 // assuming we are getting data from an async call to a db
 const names = await Name.all(); 
 res.json(names)
})
app.post('/names', async (req, res) => {
 const newName = await Name.create(req.body);
 res
 .status(201) 
 .json({ id: newName.id }) 
})
app.put('/names', async (req, res) => {
 const { id } = req.body
 const name = await Name.findAndUpdate(id, req.body);
 res
 .status(200)
 .json(name)
})
app.delete('/names', async (req, res) => {
 const { id } = req.body 
 const deleted = await Name.deleteById(id)
 res
 .status(200)
 .json({ status: 'success'})
})

Notice that we can implement "Name" class with whatever database(or file or no database) we want. As long as we keep the interface the same, we can swap different "Name" class implementations without having to change our Express routes.

One last point, since there is no "view" suggested here but we can have it if we want. For example, if for some reason, our model doesn't return us exactly what we need, maybe the key is slightly off from our API specifications, we can introduce a view layer that maps whatever the model returns us. This way we can continue to keep our Express routes very thin and handling specific to request/response related responsibilities.

answered Nov 13, 2018 at 23:56
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.