Introduction
Have you ever encountered an API endpoint that doesn't provide all the information you need in a single response? This can be frustrating, especially when you're developing a project that requires data from multiple sources. In such cases, you might find yourself having to make multiple queries to the same endpoint and combine the responses in your frontend code.
In this tutorial, we'll explore how you can create a simple Node.js server to process API responses and send the combined data back to your client in a single query. This technique can also be applied in the client-side code.
Prerequisites
Before we begin, make sure that you have the following tools installed on your system:
- Node.js
- npm (Node.js Package Manager)
Getting Started
To get started, let's create a new Node.js project. Open up your terminal and navigate to the directory where you want to create your project. Once there, run the following command:
npm init -y
This will initialize a new Node.js project with default settings. Next, let's install some dependencies that we'll need for our project:
npm install express axios
- Express: A web framework for Node.js.
- Axios: A promise-based HTTP client for making API requests.
With these dependencies installed, let's create a new file called index.js
in the root directory of our project.
In this file, we'll first import the necessary modules and set up our server:
const express = require('express');
const app = express();
const port = 8080;
This sets up a basic server that listens for requests on port 8080. You can choose any other available port if you prefer.
Next, let's create some variables to store the API endpoints we'll be querying:
const postUrl = 'https://jsonplaceholder.typicode.com/posts';
const userUrl = 'https://jsonplaceholder.typicode.com/users';
We'll be using the JSONPlaceholder API for this tutorial, which provides a set of mock endpoints for testing and prototyping.
Now, let's use the axios module to make requests to these endpoints and store the responses in files:
const fs = require('fs/promises');
const axios = require('axios');
const fetchPostsAndUsers = async () => {
try {
const [postsResponse, usersResponse] = await Promise.all([
axios.get(postUrl),
axios.get(userUrl),
]);
await fs.writeFile('posts.json', JSON.stringify(postsResponse.data));
await fs.writeFile('users.json', JSON.stringify(usersResponse.data));
} catch (error) {
console.error(error);
}
};
This code fetches data from the two API endpoints, stores the responses in files called posts.json
and users.json
, and converts the JSON data into string format using JSON.stringify()
.
Now, let's read the data from these files and combine it into a single response:
const getUsersPosts = async () => {
try {
const [postsData, usersData] = await Promise.all([
fs.readFile('posts.json', 'utf8'),
fs.readFile('users.json', 'utf8'),
]);
const posts = JSON.parse(postsData);
const users = JSON.parse(usersData);
const usersPosts = posts.map((post) => {
const user = users.find((user) => user.id === post.userId).name;
return {
...post,
user,
};
});
return usersPosts;
} catch (error) {
console.error(error);
return [];
}
};
This code reads the data from the two files using fs.readFileSync()
, parses the JSON data using JSON.parse()
, and combines the data into a single response using the map()
function.
This is where you can choose what data will be returned in the new combined response, in this example we are adding only the name property into the posts response.
Finally, let's create a new endpoint on our server that returns the combined data and call the functions:
fetchPostsAndUsers()
app.get('/posts', (req, res) => {
const usersPosts = await getUsersPosts();
res.send(usersPosts);
});
This is the final code:
const express = require('express');
const app = express();
const port = 8080;
const axios = require('axios');
const fs = require('fs/promises');
const postUrl = 'https://jsonplaceholder.typicode.com/posts/';
const userUrl = 'https://jsonplaceholder.typicode.com/users/';
const fetchPostsAndUsers = async () => {
try {
const [postsResponse, usersResponse] = await Promise.all([
axios.get(postUrl),
axios.get(userUrl),
]);
await fs.writeFile('posts.json', JSON.stringify(postsResponse.data));
await fs.writeFile('users.json', JSON.stringify(usersResponse.data));
} catch (error) {
console.error(error);
}
};
const getUsersPosts = async () => {
try {
const [postsData, usersData] = await Promise.all([
fs.readFile('posts.json', 'utf8'),
fs.readFile('users.json', 'utf8'),
]);
const posts = JSON.parse(postsData);
const users = JSON.parse(usersData);
const usersPosts = posts.map((post) => {
const user = users.find((user) => user.id === post.userId).name;
return {
...post,
user,
};
});
return usersPosts;
} catch (error) {
console.error(error);
return [];
}
};
fetchPostsAndUsers()
app.get('/posts', async (req, res) => {
const usersPosts = await getUsersPosts();
res.send(usersPosts);
});
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`);
});
In the above code, we have created a new endpoint /posts that returns an array of posts with the user field added. This is achieved by reading the data from the posts.json and users.json files and then processing the data to combine the necessary fields.
To test our endpoint, we can use a tool like Postman or just open the URL http://localhost:8080/posts in a browser. You should see a list of posts with the user field added, like this:
[
{
"userId": 1,
"id": 1,
"title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
"body": "quia et suscipit\nsuscipit... ",
"user": "Leanne Graham"
},
{
"userId": 1,
"id": 2,
"title": "qui est esse",
"body": "est rerum tempore vitae\nsequi sint... ",
"user": "Leanne Graham"
},
]
And that's it! We have successfully created a simple server that processes data from two API endpoints and returns the combined data in a single query.
This approach can be used in a variety of scenarios where you need to combine data from multiple API endpoints, and it can also be extended to handle more complex logic and data processing.
I hope you found this tutorial useful, and feel free to leave any questions or comments in the comments section below!
Top comments (1)
Awesome tutorial, i learn a lot!