Restructure Node.js API notes
This commit is contained in:
parent
9fda483399
commit
259f29743d
9 changed files with 202 additions and 219 deletions
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
categories:
|
categories:
|
||||||
- Databases
|
- Databases
|
||||||
tags: [mongo-db, node-js, mongoose]
|
tags: [mongo_db, node_js, mongoose]
|
||||||
---
|
---
|
||||||
|
|
||||||
# Create collections and documents with Mongoose
|
# Create collections and documents with Mongoose
|
||||||
|
@ -46,7 +46,7 @@ Note that we set our validation criteria as the second property for each schema
|
||||||
|
|
||||||
Note that this validation only occurs at the level of Mongoose. There is no mechanism for running the validation within the database itself. This is one of the ways that Mongo differs from an SQL database where you would be able to set the property of `required` for a cell in the table. If we didn't set any validation via Mongoose, Mongo would accept whatever we sent to it.
|
Note that this validation only occurs at the level of Mongoose. There is no mechanism for running the validation within the database itself. This is one of the ways that Mongo differs from an SQL database where you would be able to set the property of `required` for a cell in the table. If we didn't set any validation via Mongoose, Mongo would accept whatever we sent to it.
|
||||||
|
|
||||||
What is the relationship between this Mongoose validation and the [Joi](/Programming_Languages/NodeJS/REST_APIs/Validation.md) validation that we use when validating API requests in Node/Express? They complement each other. We use Joi to validate the client request to the API. If this is valid, the process would then move onto the next stage which would be transforming the data from a REST request to a database request implemented through Mongoose.
|
What is the relationship between this Mongoose validation and the [Joi](/Programming_Languages/NodeJS/REST_APIs/Validation.md) validation that we use when validating API requests in Node/Express? They complement each other. We use Joi to validate the client request to the API. If this is valid, the process would then move onto the next stage which would be transforming the data from a REST request to a database request implemented through Mongoose, where a second layer of validation would appy. We would also have validation on the client-side.
|
||||||
|
|
||||||
#### Validator functions
|
#### Validator functions
|
||||||
|
|
||||||
|
|
|
@ -1,72 +1,29 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs, mongo-db]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- rest
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Structuring Express applications
|
# Structuring Express applications
|
||||||
|
|
||||||
In the examples provided in [Creating a RESTFul API with Express](./Create_RESTful_API_with_Express.md), we had all our API routes being served via the `app` variable in `index.js`. This was very cluttered. It is best to structure your application by having a dedicated `/routes/` directory and within this, a dedicated file for each route.
|
|
||||||
|
|
||||||
In general, the following application structure works well:
|
In general, the following application structure works well:
|
||||||
|
|
||||||
```
|
```
|
||||||
\
|
\
|
||||||
routes\
|
routes\
|
||||||
|
models\
|
||||||
middlewear\
|
middlewear\
|
||||||
config\
|
config\
|
||||||
public\
|
public\
|
||||||
|
index.js
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
We will demonstrate this for the `/courses` route.
|
- **`routes/`**
|
||||||
|
|
||||||
## Using the `Router` object
|
- This should house all our RESTful API endpoints for a given resource which we define as a module. For instance if we are handling API requests to `/api/courses/` we would have a module at `/routes/courses.js`
|
||||||
Previously we instantiated an Expres instance with `app`:
|
|
||||||
|
|
||||||
```js
|
- **`models/`**
|
||||||
const express = require('express')
|
- Here we define our database schemas: definitions for the structure of the data objects we want to return from the database.
|
||||||
const app = express()
|
- In the case of Mongo we would have a file for each of our Mongoose models which will belong to an overall collection of which there are document instances.
|
||||||
```
|
- Our model files should map onto our route modules; there should generally be at least one model file for each module. The model stands as an abstract representation of the data that we will be handling with our request paths in the routes file.
|
||||||
When we partition our routes we can no longer do this, since we are only serving a single route, not the whole app, so we instead use Express's `Router` object:
|
|
||||||
|
|
||||||
```js
|
|
||||||
const router = express.Router()
|
|
||||||
```
|
|
||||||
|
|
||||||
And then update all references to `app` with `router`, e.g:
|
|
||||||
```js
|
|
||||||
router.get('/api/courses', (req, res) => {
|
|
||||||
res.send(courses)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
|
|
||||||
We would then export:
|
|
||||||
|
|
||||||
```
|
|
||||||
module.exports = router
|
|
||||||
```
|
|
||||||
|
|
||||||
Now all the functions pertaining to that route are handled in a dedicated file.
|
|
||||||
|
|
||||||
We would then import it within the main entry file, `index.js` and invoke it. The invocation syntax here is the same as when we utilise [middlewear](./Middleware.md):
|
|
||||||
|
|
||||||
```js
|
|
||||||
const courses = require('./routes/courses')
|
|
||||||
app.use('/api/courses', courses);
|
|
||||||
```
|
|
||||||
|
|
||||||
Given that we define the `courses` route in `index.js` as being served from `/api/courses`, we no longer have to use that slug within `courses.js`, we can change all our routes to `/` , e.g.
|
|
||||||
|
|
||||||
```js
|
|
||||||
router.get('/', (req, res) => {
|
|
||||||
res.send(courses)
|
|
||||||
})
|
|
||||||
```
|
|
||||||
````js
|
|
||||||
app.get("/:id", (req, res) => {
|
|
||||||
res.send(req.params.id);
|
|
||||||
});
|
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
---
|
||||||
|
categories:
|
||||||
|
- Programming Languages
|
||||||
|
- Databases
|
||||||
|
tags: [backend, node-js, REST, APIs, mongo-db]
|
||||||
|
---
|
||||||
|
|
||||||
|
# RESTful API with Node, Express and MongoDB: Integrating the database
|
||||||
|
|
||||||
|
So far we have set up the application and a `/api/courses` route which handles requests for RESTful API operations on an array of course objects. We now want to have the endpoints operate on a MongoDB `courses` collection rather than the array.
|
|
@ -1,14 +1,10 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Creating a REST API with Node and Express: Introduction
|
# RESTful API with Node, Express and MongoDB: Introduction
|
||||||
|
|
||||||
We are going to use Express to create a [RESTful API](/Databases/RESTful_APIs.md) in Node.js.
|
We are going to use Express to create a [RESTful API](/Databases/RESTful_APIs.md) in Node.js.
|
||||||
|
|
||||||
|
@ -16,37 +12,86 @@ We are going to use Express to create a [RESTful API](/Databases/RESTful_APIs.md
|
||||||
|
|
||||||
Express provides us with methods corresponding to each of the [HTTP request types](/Databases/HTTP_request_types.md):
|
Express provides us with methods corresponding to each of the [HTTP request types](/Databases/HTTP_request_types.md):
|
||||||
|
|
||||||
* `app.get()`
|
- `.get()`
|
||||||
* `app.post()`
|
- `.post()`
|
||||||
* `app.put()`
|
- `.put()`
|
||||||
* `app.delete()`
|
- `.delete()`
|
||||||
|
|
||||||
## Creating an Express instance
|
|
||||||
|
|
||||||
````js
|
|
||||||
const express = require('express')
|
|
||||||
const app = express()
|
|
||||||
````
|
|
||||||
|
|
||||||
## Our data set
|
## Our data set
|
||||||
|
|
||||||
> Typically when you create a RESTful API you are going to be returning data from a database. For simplicity we are just going simulate this with a simple data array so that we can focus on the Express syntax rather than database handling.
|
> Typically when you create a RESTful API you are going to be returning data from a database. For simplicity we are just going simulate this with a simple data array so that we can focus on the Express syntax rather than database handling. Later we will integrate this with a [MongoDB database](/Programming_Languages/NodeJS/REST_APIs/05_%20Integrating_the_database.md).
|
||||||
|
|
||||||
We will mainly work with the following array of objects:
|
We will mainly work with the following array of objects:
|
||||||
|
|
||||||
````js
|
```js
|
||||||
const courses = [
|
const courses = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "First course",
|
name: 'First course',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: "Second course",
|
name: 'Second course',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
name: "Third course",
|
name: 'Third course',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
````
|
```
|
||||||
|
|
||||||
|
## Creating an Express instance
|
||||||
|
|
||||||
|
We first create an instance of Express within `index.js`. This will be the main coordinating file and we will aim to minimise the amount of business logic we have in this file. It should really just be for initialization and managing [middleware](/Programming_Languages/NodeJS/Architecture/Middleware.md).
|
||||||
|
|
||||||
|
```js
|
||||||
|
const express = require('express');
|
||||||
|
const app = express();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Routing
|
||||||
|
|
||||||
|
We are going to receive all our HTTP requests at the path `/api/courses` and we will place all code related to this route in a dedicated Node module (`routes/courses.js`).
|
||||||
|
|
||||||
|
First we need to declare this in `index.js`:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const courses = require('./routes/courses');
|
||||||
|
app.use('/api/courses', courses);
|
||||||
|
```
|
||||||
|
|
||||||
|
Then within `courses.js` we instantiate an express router that `app.js` will route to:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const router = express.Router();
|
||||||
|
```
|
||||||
|
|
||||||
|
Our REST requests will all follow the following pattern:
|
||||||
|
|
||||||
|
```js
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
res.send(courses);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
We target the `Router` instance we created and all paths will be expressed as `/` since the app will route by default to `/courses/api` from `index.js`
|
||||||
|
|
||||||
|
## Create listener
|
||||||
|
|
||||||
|
With the routes setup and the Express instance created we can now listen for requests:
|
||||||
|
|
||||||
|
```js
|
||||||
|
app.listen(3000, () => console.log('Listening on port 30000...'));
|
||||||
|
```
|
||||||
|
|
||||||
|
## REST endpoints
|
||||||
|
|
||||||
|
We can now proceed to set up our RESTful endpoints:
|
||||||
|
|
||||||
|
[GET requests](/Programming_Languages/NodeJS/REST_APIs/1_GET.md)
|
||||||
|
|
||||||
|
[POST requests](/Programming_Languages/NodeJS/REST_APIs/2_POST.md)
|
||||||
|
|
||||||
|
[PUT requests](/Programming_Languages/NodeJS/REST_APIs/3_PUT.md)
|
||||||
|
|
||||||
|
[DELETE requests](/Programming_Languages/NodeJS/REST_APIs/4_DELETE.md)
|
||||||
|
|
|
@ -1,14 +1,10 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Creating a REST API with Node and Express: GET requests
|
# RESTful API with Node, Express and MongoDB: `GET` requests
|
||||||
|
|
||||||
With our GET request we will simply return the array of course objects.
|
With our GET request we will simply return the array of course objects.
|
||||||
|
|
||||||
|
@ -16,18 +12,15 @@ We create an [event emitter](Events%20module.md#event-emitters) and listener tha
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// Return a value as response from specified URI
|
// Return a value as response from specified URI
|
||||||
app.get('/api/courses', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
res.send(courses)
|
res.send(courses);
|
||||||
})
|
});
|
||||||
|
|
||||||
app.listen(3000, () => console.log('Listening on port 30000...'))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Our server is now set up:
|
Our server is now set up:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
|
||||||
> When creating our API this structure of creating handlers for specific routes will be iterated. Every endpoint will be specified with `[app].[http_request_type]` and followed by a callback.
|
> When creating our API this structure of creating handlers for specific routes will be iterated. Every endpoint will be specified with `[app].[http_request_type]` and followed by a callback.
|
||||||
|
|
||||||
We can now call the endpoint:
|
We can now call the endpoint:
|
||||||
|
@ -35,7 +28,7 @@ We can now call the endpoint:
|
||||||
```js
|
```js
|
||||||
const getAllCourses = async () => {
|
const getAllCourses = async () => {
|
||||||
try {
|
try {
|
||||||
const resp = await axios.get("http://localhost:3000/api/courses");
|
const resp = await axios.get('http://localhost:3000/api/courses');
|
||||||
console.log(resp.data);
|
console.log(resp.data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
@ -44,57 +37,57 @@ const getAllCourses = async () => {
|
||||||
|
|
||||||
getAllCourses();
|
getAllCourses();
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
[
|
[
|
||||||
{id: 1, name: 'First course'},
|
{id: 1, name: 'First course'},
|
||||||
{id: 2, name: 'Second course'},
|
{id: 2, name: 'Second course'},
|
||||||
{ id: 3, name: 'Third course' }
|
{id: 3, name: 'Third course'},
|
||||||
]
|
];
|
||||||
```
|
```
|
||||||
|
|
||||||
## Parameters
|
## Parameters
|
||||||
|
|
||||||
The previous example serves the entire set of our data. But we will also need to retrieve specific values, we do this by adapting the GET callback to accept parameters. These parameters will correspond to the specific entry in our main data array.
|
The previous example serves the entire set of our data. But we will also need to retrieve specific values, we do this by adapting the GET callback to accept parameters. These parameters will correspond to the specific entry in our main data array.
|
||||||
|
|
||||||
````js
|
```js
|
||||||
app.get("/api/courses/:id", (req, res) => {
|
router.get('/:id', (req, res) => {
|
||||||
res.send(req.params.id);
|
res.send(req.params.id);
|
||||||
});
|
});
|
||||||
````
|
```
|
||||||
|
|
||||||
We use the `:` symbol in the URI to indicate that we looking to parse for a specific value in the data. Now if we call `/api/courses/2`, we will get the second item in the array.
|
We use the `:` symbol in the URI to indicate that we looking to parse for a specific value in the data. Now if we call `/api/courses/2`, we will get the second item in the array.
|
||||||
|
|
||||||
The block above is the most basic format but we would want to add some kind of error handling, for example:
|
The block above is the most basic format but we would want to add some kind of error handling, for example:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.get("/api/courses/:id", (req, res) => {
|
router.get('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
if (!course) res.status(404).send("A course with the given ID was not found");
|
if (!course) res.status(404).send('A course with the given ID was not found');
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Queries
|
## Queries
|
||||||
|
|
||||||
Whereas parameters return specific data points, queries don't get data they aggregate or present the data that is returned in a certain way, such as for instance applying a search function. We indicate queries with a `?` in our URI.
|
Whereas parameters return specific data points, queries don't get data they aggregate or present the data that is returned in a certain way, such as for instance applying a search function. We indicate queries with a `?` in our URI.
|
||||||
For example: `/api/posts/2018/1?sortBy=name`.
|
For example: `/api/posts/2018/1?sortBy=name`.
|
||||||
To facilitate a request like this we have to create a GET path that allows for it:
|
To facilitate a request like this we have to create a GET path that allows for it:
|
||||||
|
|
||||||
````js
|
```js
|
||||||
app.get("/api/posts/:year/:month", (req, res) => {
|
router.get("/:year/:month", (req, res) => {
|
||||||
res.send(req.query);
|
res.send(req.query);
|
||||||
})[]();
|
})[]();
|
||||||
````
|
```
|
||||||
|
|
||||||
We would get the following back:
|
We would get the following back:
|
||||||
|
|
||||||
````json
|
```json
|
||||||
{
|
{
|
||||||
"sortBy": "name"
|
"sortBy": "name"
|
||||||
}
|
}
|
||||||
````
|
```
|
||||||
|
|
||||||
Again a JSON object with key-value pairs is returned.
|
Again a JSON object with key-value pairs is returned.
|
||||||
|
|
|
@ -1,27 +1,22 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Creating a REST API with Node and Express: POST requests
|
# RESTful API with Node, Express and MongoDB: `POST` requests
|
||||||
|
|
||||||
To demonstrate the handling of POST requests, we will create a handler that add a new element to the array of courses.
|
To demonstrate the handling of POST requests, we will create a handler that add a new element to the array of courses.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.post('/api/courses', (req, res) => {
|
router.post('/', (req, res) => {
|
||||||
const course = {
|
const course = {
|
||||||
id: courses.length + 1,
|
id: courses.length + 1,
|
||||||
name: req.body.name
|
name: req.body.name,
|
||||||
}
|
};
|
||||||
courses.push(course);
|
courses.push(course);
|
||||||
res.send(course)
|
res.send(course);
|
||||||
|
});
|
||||||
})
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Here we use the body that is sent from the client and isolate the field `name`. This presupposes that the client is sending us data with the following shape as the body:
|
Here we use the body that is sent from the client and isolate the field `name`. This presupposes that the client is sending us data with the following shape as the body:
|
||||||
|
@ -37,7 +32,7 @@ To execute the PUT request from the frontend:
|
||||||
```js
|
```js
|
||||||
const addCourse = async (newCourse) => {
|
const addCourse = async (newCourse) => {
|
||||||
try {
|
try {
|
||||||
const resp = await axios.post("http://localhost:3000/api/courses", {
|
const resp = await axios.post('http://localhost:3000/api/courses', {
|
||||||
name: newCourse,
|
name: newCourse,
|
||||||
});
|
});
|
||||||
console.log(resp.data);
|
console.log(resp.data);
|
||||||
|
@ -45,7 +40,7 @@ const addCourse = async (newCourse) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
addCourse("Biology and Life Sciences");
|
addCourse('Biology and Life Sciences');
|
||||||
```
|
```
|
||||||
|
|
||||||
Which returns:
|
Which returns:
|
||||||
|
@ -70,18 +65,19 @@ function validateCourse(course) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
We can then add the validation as part of our general error handling:
|
We can then add the validation as part of our general error handling:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.post('/api/courses', (req, res) => {
|
router.post('/', (req, res) => {
|
||||||
const course = {
|
const course = {
|
||||||
id: courses.length + 1,
|
id: courses.length + 1,
|
||||||
name: req.body.name
|
name: req.body.name,
|
||||||
}
|
};
|
||||||
const {error} = schema.validate(req.body);
|
const {error} = schema.validate(req.body);
|
||||||
if (error) return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
if (error) return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
||||||
|
|
||||||
courses.push(course);
|
courses.push(course);
|
||||||
res.send(course)
|
res.send(course);
|
||||||
})
|
});
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,39 +1,33 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Creating a REST API with Node and Express: PUT requests
|
# RESTful API with Node, Express and MongoDB: `PUT` requests
|
||||||
|
|
||||||
To demonstrate the handling of PUT requests, we will create a handler that updates an element in the course array, based on its `id` and return the updated entry:
|
To demonstrate the handling of PUT requests, we will create a handler that updates an element in the course array, based on its `id` and return the updated entry:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.put("/api/courses/:id", (req, res) => {
|
router.put('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
|
|
||||||
if (!course)
|
if (!course) return res.status(404).send('A course with the given ID was not found');
|
||||||
return res.status(404).send("A course with the given ID was not found");
|
|
||||||
const {error} = validateCourse(req.body);
|
const {error} = validateCourse(req.body);
|
||||||
|
|
||||||
if (error)
|
if (error) return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
||||||
return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
|
||||||
|
|
||||||
course.name = req.body.name;
|
course.name = req.body.name;
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Our request:
|
Our request:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const updateCourse = async (courseChange) => {
|
const updateCourse = async (courseChange) => {
|
||||||
try {
|
try {
|
||||||
const resp = await axios.put("http://localhost:3000/api/courses/1", {
|
const resp = await axios.put('http://localhost:3000/api/courses/1', {
|
||||||
name: courseChange.name,
|
name: courseChange.name,
|
||||||
});
|
});
|
||||||
console.log(resp.data);
|
console.log(resp.data);
|
||||||
|
@ -42,7 +36,7 @@ const updateCourse = async (courseChange) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
updateCourse({ name: "A new course" });
|
updateCourse({name: 'A new course'});
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Creating a REST API with Node and Express: DELETE requests
|
# RESTful API with Node, Express and MongoDB: `DELETE` requests
|
||||||
|
|
||||||
```js
|
```js
|
||||||
app.delete("/api/course/:id", (req, res) => {
|
router.delete('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
if (!course)
|
if (!course) return res.status(404).send('A course with the given ID was not found');
|
||||||
return res.status(404).send("A course with the given ID was not found");
|
|
||||||
|
|
||||||
courses.indexOf(course);
|
courses.indexOf(course);
|
||||||
courses.splice(index, 1);
|
courses.splice(index, 1);
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
|
|
||||||
```
|
```
|
|
@ -1,22 +1,22 @@
|
||||||
---
|
---
|
||||||
tags:
|
categories:
|
||||||
- Programming_Languages
|
- Programming Languages
|
||||||
- backend
|
tags: [backend, node-js, REST, APIs]
|
||||||
- node-js
|
|
||||||
- express
|
|
||||||
- REST
|
|
||||||
- apis
|
|
||||||
---
|
---
|
||||||
|
|
||||||
# Full example
|
# Full example
|
||||||
|
|
||||||
```js
|
```js
|
||||||
onst express = require("express");
|
const express = require('express');
|
||||||
const app = express(); // convention to name Express as the app
|
const app = express(); // convention to name Express as the app
|
||||||
const port = process.env.PORT || 3000;
|
const port = process.env.PORT || 3000;
|
||||||
const Joi = require("joi");
|
const Joi = require('joi');
|
||||||
const helmet = require("helmet");
|
const helmet = require('helmet');
|
||||||
const morgan = require("morgan");
|
const morgan = require('morgan');
|
||||||
|
const courses = require('./routes/courses');
|
||||||
|
|
||||||
|
// Routes
|
||||||
|
app.use('/api/courses', courses);
|
||||||
|
|
||||||
// Middlewear
|
// Middlewear
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
|
@ -25,22 +25,24 @@ app.use(helmet());
|
||||||
const courses = [
|
const courses = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
name: "First course",
|
name: 'First course',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
name: "Second course",
|
name: 'Second course',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
name: "Third course",
|
name: 'Third course',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
if (app.get("env") === "development") {
|
if (app.get('env') === 'development') {
|
||||||
app.use(morgan("common"));
|
app.use(morgan('common'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.listen(port, () => console.log(`Listening on ${port}`));
|
||||||
|
|
||||||
function validateCourse(course) {
|
function validateCourse(course) {
|
||||||
const schema = Joi.object({
|
const schema = Joi.object({
|
||||||
name: Joi.string().min(3).required(),
|
name: Joi.string().min(3).required(),
|
||||||
|
@ -50,29 +52,26 @@ function validateCourse(course) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.listen(port, () => console.log(`Listening on ${port}`));
|
|
||||||
|
|
||||||
// Return all data from API
|
// Return all data from API
|
||||||
app.get("/api/courses", (req, res) => {
|
courses.get('/', (req, res) => {
|
||||||
res.send(courses);
|
res.send(courses);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return a specific value
|
// Return a specific value
|
||||||
app.get("/api/courses/:id", (req, res) => {
|
courses.get('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
if (!course) res.status(404).send("A course with the given ID was not found");
|
if (!course) res.status(404).send('A course with the given ID was not found');
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add a new course
|
// Add a new course
|
||||||
app.post("/api/courses", (req, res) => {
|
courses.post('/', (req, res) => {
|
||||||
const schema = Joi.object({
|
const schema = Joi.object({
|
||||||
name: Joi.string().min(3).required(),
|
name: Joi.string().min(3).required(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const {error} = schema.validate(req.body);
|
const {error} = schema.validate(req.body);
|
||||||
if (error)
|
if (error) return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
||||||
return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
|
||||||
|
|
||||||
const course = {
|
const course = {
|
||||||
id: courses.length + 1,
|
id: courses.length + 1,
|
||||||
|
@ -83,31 +82,26 @@ app.post("/api/courses", (req, res) => {
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update a course
|
// Update a course
|
||||||
app.put("/api/courses/:id", (req, res) => {
|
courses.put('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
|
|
||||||
if (!course)
|
if (!course) return res.status(404).send('A course with the given ID was not found');
|
||||||
return res.status(404).send("A course with the given ID was not found");
|
|
||||||
const {error} = validateCourse(req.body);
|
const {error} = validateCourse(req.body);
|
||||||
|
|
||||||
if (error)
|
if (error) return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
||||||
return error.details.map((joiErr) => res.status(400).send(joiErr.message));
|
|
||||||
|
|
||||||
course.name = req.body.name;
|
course.name = req.body.name;
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Delete a course
|
// Delete a course
|
||||||
app.delete("/api/course/:id", (req, res) => {
|
courses.delete('/:id', (req, res) => {
|
||||||
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
const course = courses.find((c) => c.id === parseInt(req.params.id));
|
||||||
if (!course)
|
if (!course) return res.status(404).send('A course with the given ID was not found');
|
||||||
return res.status(404).send("A course with the given ID was not found");
|
|
||||||
|
|
||||||
courses.indexOf(course);
|
courses.indexOf(course);
|
||||||
courses.splice(index, 1);
|
courses.splice(index, 1);
|
||||||
|
|
||||||
res.send(course);
|
res.send(course);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
Loading…
Add table
Reference in a new issue