0 likes | 312 Views
https://techvidvan.com/tutorials/restful-api-nodejs/
E N D
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.
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' }, ];
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:
● 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. 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
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" }
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
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}`); });
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.
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:-
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.
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;
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.
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.
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");
// *** 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");
}; 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",
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.