Post

Api development tutorial for Web Developers

API Development Tutorial: A Hands-On Guide

Welcome to this tutorial designed for web developers who are new to working with APIs! This guide will walk you through a series of exercises to help you understand how to fetch and display data from APIs using Node.js and a popular frontend framework, React.

Prerequisites

Before we begin, please make sure you have the following installed and ready to go:

  • Node.js & npm: You’ll need Node.js installed to run both our backend and frontend projects. npm is included with Node.js.
  • A code editor: VS Code, Sublime Text, or any other editor you’re comfortable with.
  • Basic knowledge of JavaScript: We will be using ES6 features like async/await and arrow functions.
  • Basic understanding of React: Familiarity with functional components, state, and hooks (useState, useEffect).

Exercise 1: Fetching Data with Node.js (Backend)

In this exercise, we’ll create a simple Node.js script to fetch a list of posts from a public mock API called JSONPlaceholder. This will teach you the fundamentals of making an HTTP request from a backend environment.

Step 1: Initialize Your Project

First, create a new directory for your project and initialize it with npm.

1
2
3
4
mkdir api-nodejs-exercise
cd api-nodejs-exercise
npm init -y

Step 2: Install Dependencies

We’ll use a library called axios to make our HTTP requests. It’s a very popular and easy-to-use library for this purpose.

1
2
npm install axios

Step 3: Write the Fetching Script Create a new file named fetchPosts.js. Inside this file, we will write our code to fetch the data.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// fetchPosts.js

const axios = require('axios');

async function fetchPosts() {
  try {
    // Make a GET request to the JSONPlaceholder API for a list of posts
    const response = await axios.get('https://jsonplaceholder.typicode.com/posts');

    // The data is in the `response.data` property
    const posts = response.data;

    // Log the first post to the console to see the structure
    console.log('Successfully fetched posts!');
    console.log('First post:', posts[0]);

  } catch (error) {
    // Log any errors that occur
    console.error('An error occurred while fetching posts:', error.message);
  }
}

// Call the function to run the script
fetchPosts();


Step 4: Run the Script

Run your script from the terminal. You should see a successful message and the details of the first post printed.

1
node fetchPosts.js

Exercise 2: Displaying Data with React (Frontend)

Now let’s move to the frontend. We’ll create a React component that fetches the same data from JSONPlaceholder and displays it in a list. This exercise introduces the crucial concept of using a component’s lifecycle to fetch data.

Step 1: Create a New React App

If you don’t already have one, create a new React project using Vite.

1
2
3
4
5
npm create vite@latest api-react-exercise -- --template react
cd api-react-exercise
npm install
npm run dev

** Step 2: Write the React Component **

Open the src directory and replace the contents of App.jsx with the following code. This component will use useState to store the fetched data and useEffect to trigger the API call when the component mounts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// src/App.jsx

import React, { useState, useEffect } from 'react';

function App() {
  // Use state to store the posts data and a loading indicator
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Define an async function to fetch the data
    const fetchPosts = async () => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts');
        const data = await response.json();

        // Update the state with the fetched data
        setPosts(data);
      } catch (error) {
        console.error('Failed to fetch posts:', error);
      } finally {
        // Set loading to false once the fetch is complete
        setLoading(false);
      }
    };

    // Call the fetch function
    fetchPosts();
  }, []); // The empty dependency array ensures this effect runs only once, on mount

  if (loading) {
    return <div className="text-center p-8">Loading posts...</div>;
  }

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-3xl font-bold mb-6 text-center">Posts from an API</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {posts.map(post => (
          <div key={post.id} className="bg-white rounded-lg shadow-md p-6 border border-gray-200">
            <h2 className="text-xl font-semibold mb-2">{post.title}</h2>
            <p className="text-gray-700">{post.body}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;

Step 3: Run the App

Save the file and check your browser at http://localhost:5173. You should see a list of posts rendered on the page!

Exercise 3: Building a Simple Full-Stack App (Node.js + React)

This is the final, most comprehensive exercise. We’ll combine our backend and frontend skills to create a simple full-stack application. The React app will now fetch data from our own Node.js server, which in turn fetches the data from the public API.

This introduces a common pattern where your frontend communicates with your own backend to get data, rather than calling external APIs directly. This is often necessary for security, performance, or data manipulation reasons. Step 1: Set up the Backend (Express Server)

Let’s return to the api-nodejs-exercise directory. We’ll now turn it into a simple web server using Express.

First, install Express and CORS. CORS (Cross-Origin Resource Sharing) is a security feature that we need to handle when a frontend on one domain (e.g., localhost:5173) tries to make a request to a backend on another domain (e.g., localhost:3000).

1
npm install express cors

Next, create a file named server.js and add the following code. This server will have one endpoint, /api/posts, which fetches the posts from JSONPlaceholder and sends them back as JSON.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// server.js

const express = require('express');
const cors = require('cors');
const axios = require('axios');

const app = express();
const port = 3000;

// Use the cors middleware to allow requests from our React app
app.use(cors());

// Define an API endpoint
app.get('/api/posts', async (req, res) => {
  try {
    // Fetch data from the public API
    const response = await axios.get('https://jsonplaceholder.typicode.com/posts');

    // Send the data back to our frontend
    res.json(response.data);
  } catch (error) {
    console.error('Error fetching posts:', error.message);
    res.status(500).json({ error: 'Failed to fetch posts' });
  }
});

// Start the server
app.listen(port, () => {
  console.log(`Server listening at http://localhost:${port}`);
});

Now, start the server from your terminal:

1
node server.js

Step 2: Update the Frontend (React App)

Go back to your api-react-exercise directory. We need to modify App.jsx to fetch data from our new Express server instead of the public API directly.

Change the fetch URL in your useEffect hook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// src/App.jsx (updated)

import React, { useState, useEffect } from 'react';

function App() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchPosts = async () => {
      try {
        // Change the URL to point to our local Express server
        const response = await fetch('http://localhost:3000/api/posts');
        const data = await response.json();
        setPosts(data);
      } catch (error) {
        console.error('Failed to fetch posts:', error);
      } finally {
        setLoading(false);
      }
    };

    fetchPosts();
  }, []);

  if (loading) {
    return <div className="text-center p-8">Loading posts...</div>;
  }

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-3xl font-bold mb-6 text-center">Posts from My API Server</h1>
      <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        {posts.map(post => (
          <div key={post.id} className="bg-white rounded-lg shadow-md p-6 border border-gray-200">
            <h2 className="text-xl font-semibold mb-2">{post.title}</h2>
            <p className="text-gray-700">{post.body}</p>
          </div>
        ))}
      </div>
    </div>
  );
}

export default App;

** Step 3: Test the Full-Stack App **

Make sure both your Node.js server (node server.js) and your React app (npm run dev) are running in separate terminals. If everything is configured correctly, your React app will now display the data fetched from your own local backend.

Bonus Exercise: Handling POST Requests

So far, we’ve only used GET requests to retrieve data. Most APIs also support POST requests, which are used to send new data to the server (e.g., creating a new post, submitting a form).

Here’s a simple example of how to make a POST request using fetch to create a new post on JSONPlaceholder. You could integrate this into your React app with a form.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Example of a POST request

const createPost = async () => {
  try {
    const newPost = {
      title: 'My New Awesome Post',
      body: 'This is the content of my brand new post.',
      userId: 1,
    };

    const response = await fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(newPost),
    });

    const data = await response.json();
    console.log('New post created:', data);
  } catch (error) {
    console.error('Failed to create post:', error);
  }
};

This post is licensed under CC BY 4.0 by the author.