The document discusses RESTful API development in Node.js. It covers fundamentals like HTTP methods, resource design, authentication and error handling. It provides a code example of a RESTful API for a library with endpoints for getting, adding, updating and deleting books from the library collection. The API uses Express.js and adheres to REST principles by utilizing HTTP methods on resources identified by URLs.
Handwritten Text Recognition for manuscripts and early printed texts
RESTful API in Node.pdf
1. RESTful API in Node.js
RESTful API (Representational State Transfer) has become the de facto
standard for building web services due to its simplicity, scalability, and ease of
integration. In this article, we will explore the fundamentals of RESTful API
development, covering various aspects, including HTTP methods, resource
design, authentication, error handling, and more. We will also provide code
examples in a popular programming language to illustrate each topic.
What is REST architecture?
Specifically, REST stands for REpresentational State Transfer. REST is an
HTTP-based architecture that is built on web standards. Every component is a
resource, and each resource is accessible through a common interface utilising
HTTP standard techniques. In 2000, Roy Fielding made the first mention of
REST.
Resources are merely made accessible by a REST server, and REST clients use
the HTTP protocol to access and modify the resources. Each resource in this
place is recognised by URIs or global IDs. While text, JSON, and XML are all
used in REST to describe resources, JSON is the most often used format.
HTTP methods:
GET: Retrieves data from a specified resource.
POST: Submits data to be processed or creates a new resource.
2. PUT: Updates or replaces an existing resource with new data.
DELETE: Removes a specified resource from the server.
RESTful web services
RESTful web services are a type of architectural style for designing networked
applications that adhere to the principles of Representational State Transfer
(REST). RESTful web services are based on the HTTP protocol and use
standard HTTP methods (GET, POST, PUT, DELETE) to perform operations
on resources identified by URLs. They emphasize statelessness, scalability,
and interoperability between different systems, allowing clients to access and
manipulate resources over the Internet using a uniform interface. RESTful
web services typically exchange data in formats such as JSON or XML and are
widely used in building web APIs.
RESTful for A Library
To create a RESTful API for a library, you can define endpoints that represent
the resources within the library.
Here’s an example of how you can structure the API:
const express = require('express');
const app = express();
app.use(express.json());
// Sample data
let books = [
{ id: 1, title: 'Book 1', author: 'Author 1' },
{ id: 2, title: 'Book 2', author: 'Author 2' },
];
3. 1. Retrieve a list of books:
● Method: GET
● Endpoint: /books
● Description: Returns a list of all books in the library.
// Retrieve a list of books
app.get('/books', (req, res) => {
res.json(books);
});
2. Retrieve a specific book:
● Method: GET
● Endpoint: /books/{id}
● Description: Returns the details of a specific book identified by its
unique ID.
// Retrieve a specific book
app.get('/books/:id', (req, res) => {
const bookId = parseInt(req.params.id);
const book = books.find((b) => b.id === bookId);
if (book) {
res.json(book);
} else {
res.status(404).json({ message: 'Book not found' });
}
});
3. Add a new book:
4. ● Method: POST
● Endpoint: /books
● Description: Creates a new book in the library with the provided
details.
// Add a new book
app.post('/books', (req, res) => {
const { title, author } = req.body;
const newBook = { id: books.length + 1, title, author };
books.push(newBook);
res.status(201).json(newBook);
});
4. Update an existing book:
Advertisement
● Method: PUT
● Endpoint: /books/{id}
● Description: Updates the details of a specific book identified by its
ID.
// Update an existing book
app.put('/books/:id', (req, res) => {
const bookId = parseInt(req.params.id);
const { title, author } = req.body;
const bookIndex = books.findIndex((b) => b.id === bookId);
if (bookIndex !== -1) {
books[bookIndex] = { id: bookId, title, author };
res.json(books[bookIndex]);
} else {
res.status(404).json({ message: 'Book not found' });
}
});
5. 5. Delete a book:
● Method: DELETE
● Endpoint: /books/{id}
● Description: Deletes a specific book identified by its ID.
// Delete a book
app.delete('/books/:id', (req, res) => {
const bookId = parseInt(req.params.id);
const bookIndex = books.findIndex((b) => b.id === bookId);
if (bookIndex !== -1) {
const deletedBook = books.splice(bookIndex, 1);
res.json(deletedBook[0]);
} else {
res.status(404).json({ message: 'Book not found' });
}
});
6. Start the Server:
// Start the server
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Note: Remember to install the necessary dependencies (such as Express.js)
using npm before running the code.
You can further expand the API to include additional endpoints for managing
other resources like authors, genres, or book loans. Additionally, you may
6. consider implementing authentication and authorization mechanisms to
secure the API and restrict access to certain operations.
Output:
The output for the above code will depend on the requests made to the API
endpoints. Here’s an example of the expected output for each endpoint:
1. GET ‘/books’ – Retrieve a list of books:
Response:
[
{ "id": 1, "title": "Book 1", "author": "Author 1" },
{ "id": 2, "title": "Book 2", "author": "Author 2" }
]
2. GET ‘/books/{id}’ – Retrieve a specific book:
Response (e.g., for ‘/books/1’):
{ "id": 1, "title": "Book 1", "author": "Author 1" }
3. POST ‘/books’ – Add a new book:
Request Body:
{ "title": "Book 3", "author": "Author 3" }
7. Response:
{ "id": 3, "title": "Book 3", "author": "Author 3" }
4. PUT ‘/books/{id}’ – Update an existing book:
Request Body:
{ "title": "Updated Book 1", "author": "Updated Author 1" }
Response:
{ "id": 1, "title": "Updated Book 1", "author": "Updated Author
1" }
5. DELETE ‘/books/{id}’ – Delete a book:
Response (e.g., for ‘/books/2’):
{ "id": 2, "title": "Book 2", "author": "Author 2" }
Creating an own RESTful API to have a
better understanding
8. Step 1: Set Up a New Project Create a new directory for your project and
initialize a new Node.js project. Open your terminal and run the following
commands:
mkdir my-restful-api
cd my-restful-api
npm init -y
Step 2: Install Dependencies Next, install the required dependencies:
Express.js and body-parser. Body-parser is used to parse incoming request
bodies.
npm install express body-parser
Step 3: Create the Server File. Create a new file named server.js in your project
directory. Open the file and add the following code:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
app.use(bodyParser.json());
// Define your routes and endpoints here
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
9. Step 4: Define Endpoints Inside the server.js file, you can now define your API
endpoints.
Here’s an example of how you can define a simple endpoint to retrieve a list of
books:
let books = [
{ id: 1, title: 'Book 1', author: 'Author 1' },
{ id: 2, title: 'Book 2', author: 'Author 2' },
];
// GET /books
app.get('/books', (req, res) => {
res.json(books);
});
Step 5: Run the Server To start the server and test your API, run the following
command in your terminal:
node server.js
You should see the message “Server is running on port 3000” in the console,
indicating that your server is up and running.
Step 6: Test the API. You can now test your API endpoints using a tool like
Postman or by making HTTP requests using a programming language of your
choice. For example, you can send a GET request to
http://localhost:3000/books to retrieve the list of books.
10. Congratulations! We have created a basic RESTful API using Node.js and
Express.js. You can continue to expand your API by adding more endpoints,
implementing CRUD operations, and incorporating additional features and
functionalities as per your requirements.
OUTPUT:-
Starting the Server:-
The server is running on port 3000
Make a GET request to ‘http://localhost:3000/books’: Response:
[
{ "id": 1, "title": "Book 1", "author": "Author 1" },
{ "id": 2, "title": "Book 2", "author": "Author 2" }
]
This output indicates that the server is running, and the ‘/book’s endpoint is
successfully returning a list of books in JSON format.
You can continue to test the API by making requests to other endpoints you
define and handle the corresponding responses based on your
implementation.
REST API Best Practices
Versioning:-
11. Versioning is an essential best practice in REST API design to allow for future
updates and changes without breaking existing clients. Versioning ensures
that clients relying on the API can continue to function correctly even as the
API evolves. Here are some recommended practices for versioning REST APIs:
1. URL Versioning: One common approach is to include the version number in
the URL path. For example:
https://api.example.com/v1/resource
This approach clearly indicates the version being used and allows for multiple
versions to coexist.
2. Custom Request Headers: Another option is to use custom headers to
specify the API version. For instance, you could include a “X-API-Version”
header in the request, indicating the desired API version. This approach keeps
the URL cleaner and allows for version negotiation between clients and
servers.
3. Query Parameters: Versioning can also be achieved by including a query
parameter in the request URL.
For example:
https://api.example.com/resource?version=1
This approach allows clients to specify the desired version explicitly.
12. Now let’s see how versioning can be
implemented:-
Let’s transfer our routes directory to the new v1 directory.
# Get the path to your current directory (copy it)
pwd
# Move "routes" into "v1" (insert the path from above into
{pwd})
mv {pwd}/src/routes {pwd}/src/v1
All of our routes for version 1 will be kept in the brand-new directory
/src/v1/routes. Later, we’ll add “real” content. But first, let’s test things out by
adding a straightforward index.js file.
# In /src/v1/routes
touch index.js
We turn on a basic router inside.
// In src/v1/routes/index.js
const express = require("express");
const router = express.Router();
router.route("/").get((req, res) => {
res.send(`<h2>Hello from ${req.baseUrl}</h2>`);
});
module.exports = router;
13. Now, we need to connect our router for version 1 inside of src/index.js, which
is our root entry point.
// In src/index.js
const express = require("express");
// *** ADD ***
const v1Router = require("./v1/routes");
const app = express();
const PORT = process.env.PORT || 3000;
// *** REMOVE ***
app.get("/", (req, res) => {
res.send("<h2>It's Working!</h2>");
});
// *** ADD ***
app.use("/api/v1", v1Router);
app.listen(PORT, () => {
console.log(`API is listening on port ${PORT}`);
});
In your browser, go to localhost:3000/api/v1 and you should see the
following:
The project has just been organized to handle various versions. As of right
now, we are sending all incoming requests marked “/api/v1” to our version 1
router, which will later direct each request to the appropriate controller
method.
14. Name Resources in Plural
After everything is set up, we can begin the actual API implementation. As I
previously stated, I’d like to begin with our basic CRUD endpoints.
Or to put it another way, let’s begin implementing endpoints for adding,
reading, editing, and removing workouts.
Let’s first connect a particular controller, service, and router for our exercises.
touch src/controllers/workoutController.js
touch src/services/workoutService.js
touch src/v1/routes/workoutRoutes.js
I always prefer to begin with the routes. Let’s consider what to call our
endpoints. This is related to these specific best practices.
Since we only want to add one workout, we could give the creation endpoint
the name “workout” (/api/v1). In general, there is nothing wrong with that
strategy; however, it may cause misunderstandings.
Always keep in mind that your API should be accurate because it is used by
other people. This also applies to how you name your resources.
A resource always looks like a box to me. In our illustration, the box is a
collection that houses various exercises.
15. The major benefit of naming your resources in the plural is that it is
immediately obvious to other people that this is a collection of various
exercises.
// In src/v1/routes/workoutRoutes.js
const express = require("express");
const router = express.Router();
router.get("/", (req, res) => {
res.send("Get all workouts");
});
router.get("/:workoutId", (req, res) => {
res.send("Get an existing workout");
});
router.post("/", (req, res) => {
res.send("Create a new workout");
});
router.patch("/:workoutId", (req, res) => {
res.send("Update an existing workout");
});
router.delete("/:workoutId", (req, res) => {
res.send("Delete an existing workout");
});
module.exports = router;
You can remove the index.js test file from the src/v1/routes directory.
Let’s connect the v1 workout router to our entry point now.
// In src/index.js
const express = require("express");
16. // *** REMOVE ***
const v1Router = require("./v1/routes");
// *** ADD ***
const v1WorkoutRouter = require("./v1/routes/workoutRoutes");
const app = express();
const PORT = process.env.PORT || 3000;
// *** REMOVE ***
app.use("/api/v1", v1Router);
// *** ADD ***
app.use("/api/v1/workouts", v1WorkoutRouter);
app.listen(PORT, () => {
console.log(`API is listening on port ${PORT}`);
That was easy, right? With our v1WorkoutRouter, we are currently catching all
requests that are directed to /api/v1/workouts.
For each different endpoint, we will call a different method managed by our
controller inside of our router.
Make a method for every endpoint, please. For the time being, just replying
with a message should work.
// In src/controllers/workoutController.js
const getAllWorkouts = (req, res) => {
res.send("Get all workouts");
};
const getOneWorkout = (req, res) => {
res.send("Get an existing workout");
};
const createNewWorkout = (req, res) => {
res.send("Create a new workout");
17. };
const updateOneWorkout = (req, res) => {
res.send("Update an existing workout");
};
const deleteOneWorkout = (req, res) => {
res.send("Delete an existing workout");
};
module.exports = {
getAllWorkouts,
getOneWorkout,
createNewWorkout,
updateOneWorkout,
deleteOneWorkout,
};
It’s time to use the controller methods and slightly refactor our workout router
at this point.
// In the file "workoutRoutes.js"
const workoutController =
require("../../controllers/workoutController"); const express =
require("express");
express.Router(); const router;
workoutController.getAllWorkouts; router.get("/");
workoutController.getOneWorkout; router.get("/:workoutId",
workoutController.createNewWorkout = router.post("/");
workoutController.updateOneWorkout; router.patch("/:workoutId",
workoutController.deleteOneWorkout; router.delete("/:workoutId",
18. exports.module = router;
By entering localhost:3000/api/v1/workouts/2342 into the browser, we can
now test our GET /api/v1/workouts/:workoutId endpoint. You ought to see
something similar to this:
We succeeded! We have finished the first layer of our architecture. Let’s
implement the following best practice and then build our service layer.
Conclusion
RESTful web services provide a standardized and efficient way of designing
and implementing APIs for networked applications. By adhering to the
principles of REST, such as using HTTP methods and leveraging a uniform
interface, RESTful APIs promote scalability, statelessness, and
interoperability between different systems.
When creating a RESTful API, it is essential to define clear endpoints that
represent the resources and operations available. The API should follow the
HTTP methods (GET, POST, PUT, DELETE) to perform actions on the
resources identified by URLs. Additionally, data exchange formats like JSON
or XML are commonly used to transfer information between clients and
servers.