In the last part of this series, we outline steps to set up the project structure. If you have not read the article, click the link: PERN stack Series 2: Project Setup - Todo application to read.
Today, we will be setting up the server side of our application. However, before we do so, we will touch on RESTful API as it is relevant to our project.
RESTful API
This stands for Representational State Transfer and is an architectural style for designing networked applications. It is an approach to building web services that are scalable, stateless, and follow a set of constraints and principles.
Here are some key concepts associated with RESTful APIs:
RESTful API, which stands for Representational State Transfer, is an architectural style for designing networked applications. It is an approach to building web services that are scalable, stateless, and follow a set of constraints and principles. Here are some key concepts associated with RESTful APIs:
Resources: In a RESTful API, everything is considered a resource. Resources can be entities like objects, services, or concepts. Each resource is identified by a unique URI (Uniform Resource Identifier).
HTTP Methods (CRUD): RESTful APIs use standard HTTP methods for performing operations on resources. The four main HTTP methods mapped to CRUD operations are:
GET: Retrieve a representation of a resource.
POST: Create a new resource.
PUT: Update a resource or create a new resource if it doesn't exist.
DELETE: Remove a resource.
Statelessness: Each request from a client to a server must contain all the information needed to understand and fulfil the request. The server should not store any information about the client's state between requests.
Representation: Resources can have multiple representations, such as JSON, XML, or HTML. The client and server can negotiate the representation during communication.
Now we have that out of the way, let's continue building! ๐
Create connection to Postgres database
Create a file called "db.js"
, copy and paste the code below in the file
const Pool = require("pg").Pool;
const pool = new Pool({
user: "postgres",
password: "admin123",
host: "localhost",
port: "5432",
database: "mytodo_db"
});
module.exports = pool;
This code exports a PostgreSQL connection pool instance using the pg
library. Here's a breakdown of the code:
Importpg.Pool
:
The
Pool
class from thepg
library is imported. This class is used to create a pool of PostgreSQL client connections.Create a PostgreSQL Connection Pool:
The
pool
constant is assigned a new instance of thePool
class, which is configured with the connection details for the PostgreSQL database.user
: The username for connecting to the database.password
: The password for connecting to the database.host
: The hostname of the PostgreSQL server.port
: The port on which the PostgreSQL server is running.database
: The name of the database.
Export the Pool Instance:
- The
pool
instance is exported as a module, making it available for use in other parts of your application.
- The
Create Entry Point
we will create a file called index.js which will serve as our entry point. In the context of a system or application, an "entry point" refers to the point at which execution begins.
make sure you are in the server folder
cd server
touch index.js
inside the index.js, copy and paste the code below.
const express = require("express");
const app = express();
const cors = require("cors");
const pool = require("./db");
const { Query } = require("pg");
//middleware
app.use(cors());
app.use(express.json());
//Routes
//create a todo
app.post("/todos", async(req,res) => {
try {
const query = "INSERT INTO todo(description) VALUES ($1) RETURNING *";
const { description } = req.body
const newTodo = await pool.query(query,[description]);
res.json(newTodo.rows[0]);
} catch (err) {
console.log(err.message);
}
});
//get all todos
app.get("/todos", async(req,res) => {
try{
const query = "SELECT * FROM todo"
const allTodos = await pool.query(query,);
res.json(allTodos.rows);
} catch (err) {
console.log(err.message);
}
});
//get a todo
app.get("/todos/:id", async(req,res) => {
try {
const query = "SELECT * FROM todo WHERE todo_id = $1";
const { id } = req.params;
const todo = await pool.query(query, [id]);
res.json(todo.rows[0]);
} catch (err) {
console.log(err.message);
}
});
//update a todo
app.put("/todos/:id", async(req,res) => {
try {
const query = "UPDATE todo SET description = $1 WHERE todo_id = $2 RETURNING *";
const { id } = req.params;
const { description } = req.body;
const updateTodo = await pool.query(query,
[description, id]
);
res.json(updateTodo.rows[0]);
} catch (err) {
console.log(err.message);
}
});
//delete a todo
app.delete("/todos/:id", async(req,res) => {
try {
const query = "DELETE FROM todo WHERE todo_id = $1";
const { id } = req.params;
const deleteTodo = await pool.query(query,
[ id ]
);
res.json("To-do was deleted");
} catch (err) {
console.log(err.message);
}
});
app.listen(4000, () => {
console.log("server has started on port 4000");
});
Here's a breakdown of the code:
Imports:
express
: The Express.js framework for handling HTTP requests and routes.cors
: Middleware to enable Cross-Origin Resource Sharing.pool
: Connection pool to interact with the PostgreSQL database.Query
frompg
: A utility for executing SQL queries.
Middleware:
cors
: Configures Cross-Origin Resource Sharing to allow the API to be accessed from different domains.express.json()
: Middleware to parse incoming JSON requests.
Routes:
Create a Todo (
POST /todos
):- Inserts a new todo into the database and returns the created todo.
Get All Todos (
GET /todos
):- Retrieves all todos from the database.
Get a Todo (
GET /todos/:id
):- Retrieves a specific todo based on the provided
id
parameter.
- Retrieves a specific todo based on the provided
Update a Todo (
PUT /todos/:id
):- Updates the description of a specific todo based on the provided
id
parameter.
- Updates the description of a specific todo based on the provided
Delete a Todo (
DELETE /todos/:id
):- Deletes a specific todo based on the provided
id
parameter.
- Deletes a specific todo based on the provided
Server Setup:
- The server listens on port 4000, and a message is logged to the console when the server starts.
Current project structure:
Testing our APIs
Prerequisite:
Postman: this will be used to test, and manage our RESTful APIs. watch this YouTube video by Automation step by step, to get started with Postman.
make sure
nodemon
is installed.
Start server: run the command below to start the server.
nodemon index.js
Testing endpoints with Postman
- Create: We can create a new todo by sending an HTTP POST request to the endpoint,
"
http://localhost:4000/todos
"
- Read: To access all todos we have created, we perform a HTTP POST request to the endpoint,
"
http://localhost:4000/todos
"
- Read: To access a todo, we perform a HTTP GET request to the endpoint,
"
http://localhost:4000/todos/2
"
, and we specify an id parameter,"2"
.
- Update: To edit a todo, we perform an HTTP PUT request to the endpoint,
"
http://localhost:4000/todos
/2"
, we specify an id parameter, "2", and specify"description"
as JSON in the body of the request.
- DELETE: To access a todo, we perform a HTTP DELETE request to the endpoint,
"http://localhost:4000/todod/2"
, and we specify an id parameter, "2".
Yes, you did it, well done! - our endpoints are functioning properly!
Conclusion
The article delves into the fundamental principles of RESTful API design, emphasizing scalability, statelessness, and adherence to a set of core principles. Concepts like resources, HTTP methods (GET, POST, PUT, DELETE), statelessness, and representation are explored to provide a comprehensive understanding.
The practical implementation includes the creation of a connection to a PostgreSQL database through the "db.js" file, which exports a well-configured PostgreSQL connection pool instance. The code intricately details the import of the pg.Pool
class, the configuration of the connection pool with specific database details, and the subsequent export of the pool instance for broader application use.
The article proceeds to establish an entry point for the server in the "index.js" file, leveraging the Express.js framework. This setup incorporates middleware for CORS and JSON parsing, defines routes for CRUD operations on a "todo" resource, and seamlessly interacts with the PostgreSQL database using the exported connection pool instance.
The provided code not only demonstrates the implementation of a robust RESTful API for todo management but also elucidates endpoints for creating, retrieving, updating, and deleting todo items.