In this tutorial, we'll create a simple REST API in Express, that we can invoke from a frontend to get domain suggestions. We'll start setting up a basic Express server that handles only a POST request, and we'll create a small frontend to invoke it. This server will receive a description of what the user is looking for and, for the purpose of this example, will respond with a mock array of domain suggestions.
We first create a new directory for the rest api server project, navigate into it, initialize a new Node.js project and Install Express:
mkdir my-domain-search-app
cd my-domain-search-app
npm init -y
npm install express
Create a file named server.js in the root of your project directory and add the following code to set up a basic Express server:
const express = require('express');
const bodyParser = require('body-parser');
const app = express();
const port = 3000;
// Middleware to parse JSON bodies
app.use(bodyParser.json());
// Handle CORS - This is required for the frontend to communicate with the backend
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header(
'Access-Control-Allow-Headers',
'Origin, X-Requested-With, Content-Type, Accept'
);
next();
});
// POST endpoint for domain suggestions
app.post('/api/domain-suggestions', (req, res) => {
const description = req.body.description;
console.log(`Received description: ${description}`);
// Mock response - replace this with actual logic to generate domain suggestions
const suggestions = [
`${description}-online.com`,
`${description}hub.com`,
`get${description}.com`
];
res.json({success: true, suggestions});
});
app.listen(port, () => {
console.log(`Server running at http://localhost:${port}/`);
});
Start your server by running:
npm run start
Or, if you set up your package.json's scripts to include a command for starting the server, use that command. By default, node server.js should suffice.
The Express server is now set up to handle POST requests at /api/domain-suggestions and will return a mock list of domain suggestions based on the description sent in the request body. Remember, the actual logic for generating domain suggestions (e.g., calling an external API or algorithm) should replace the mock logic provided in the example.
In the previous point we created a project using npm init, then we added express as an npm package. However, if we want a more structured project we can use the express generator to generate a project using the default template.
To connect the frontend to the Express backend, we need to modify the JavaScript in the HTML file to make an AJAX call (using fetch, for example) to the new endpoint when the form is submitted. Here is an example snippet of the frontend code:
document.getElementById('domainSearchForm').addEventListener('submit', async function(event) {
event.preventDefault(); // Prevent the default form submission
const description = document.getElementById('descriptionInput').value;
// Make the API call to the Express backend
try {
const response = await fetch('http://localhost:3000/api/domain-suggestions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ description }),
});
if (response.ok) {
const data = await response.json();
console.log('Suggestions:', data.suggestions);
// Process your suggestions here
} else {
console.error('Failed to fetch suggestions');
}
} catch (error) {
console.error('Error:', error);
}
});
This code sends the description to the Express server and logs the suggested domains to the console. Later on, we can expand this by displaying the suggestions on the webpage.
By definition the REST API does not impose a set of strict rules, but it should follow the design principles of the representational state transfer (REST) architectural style:
Uniform Interface: API requests for the same resource must be consistent, regardless of the request's origin. Resources should be uniquely identifiable through a URI and designed to be neither too large nor lacking necessary information.
Client-Server Decoupling: Client and server applications should operate independently, with the client knowing only the URI of requested resources. Servers should not alter client applications except to deliver requested data.
Statelessness: Each request must contain all information required for processing, eliminating the need for server-side sessions or data storage related to client requests.
Cacheability: Resources should support caching to enhance performance and scalability, with server responses indicating cacheability.
Layered System Architecture: RESTful communication may pass through multiple intermediaries without client or server being able to discern direct or indirect connections, ensuring flexibility in network setups.
Code on Demand (Optional): While REST APIs typically deliver static resources, they can also provide executable code on demand to enhance functionality, such as Java applets, but this is optional.
When implementing a REST API in Express.js, there are several best practices and important points that we should consider to ensure the API is robust, secure, efficient, and easy to maintain.
Use the appropriate HTTP status codes to indicate the success or failure of an API request. For example, 200 (OK), 201 (Created), 400 (Bad Request), 404 (Not Found), 500 (Internal Server Error), etc.
This is something that is not specific to REST apis, but to any express application. Middleware functions can execute code, make changes to the request and response objects, end the request-response cycle, and call the next middleware function.
Common uses include request logging, authentication, body parsing, and handling CORS.
API versioning (e.g., /api/v1/resource) allows to make changes to the API without breaking existing clients.
Implement centralized error handling to catch and respond to errors consistently. Use try-catch for asynchronous code to handle exceptions.
Log requests, responses, and errors to help with debugging and monitoring. Consider using a logging library that supports different log levels (e.g., winston, morgan).
Document your API endpoints, request parameters, and response formats. Tools like Swagger (OpenAPI) can help generate interactive API documentation.
It's a good practice to validate input data both on the client and server side to ensure your API receives the correct data format and values. The server should always implement a validation mechanism.
If your API is accessed from different domains, configure CORS correctly to allow or restrict access.
Implement rate limiting to protect your API against brute-force attacks or overly frequent requests from a single client. By focusing on these aspects, you can create an Express.js REST API that is not only functional and user-friendly but also secure, reliable, and scalable.
If you want to use ES Module Libraries from CommonJS Apps or you endup in a version or depdency hell, or even want to use nodejs libraries from other languanges like python you can easily expose them as APIs
Middleware in Express sorts out requests and responses, tackling everything from data parsing to security. Though often misunderstood, getting a grip on the different types and their order can seriously level up your web apps, making them slick, secure, and speedy.