Next.js Tutorial: Creating a Metals Market Data Application with Cacheing

In this tutorial, we will create a Next.js application that fetches market data from an API, caches it locally, and serves it through an API endpoint to keep the secret safe. The cache will refresh every minute, allowing efficient use of the API without excessive calls.

Step 1: Set Up Your Next.js Application

First, make sure you have Node.js installed on your machine. If you haven’t already set up a Next.js application, you can create one using the following command:

npx create-next-app@latest metals-market-app
cd metals-market-app

Step 2: Install Axios

We will use Axios to fetch data from the API. Install Axios with the following command:

npm install axios

Step 3: Create the API Route

Next.js allows you to create API routes easily. Create a new directory named api inside the pages directory, and then create a file named metals.js inside the api directory.

mkdir pages/api
touch pages/api/metals.js

Step 4: Implement Caching Logic in the API Route

Now, open pages/api/metals.js and implement the logic to fetch and cache the market data.

// pages/api/metals.js
import axios from 'axios';

let cache = null; // Variable to hold cached data
let lastFetched = null; // Variable to track last fetch time

const API_KEY = 'YOUR-API-KEY'; // Replace with your actual API key
const API_URL = 'https://metals.g.apised.com/v1/market-data?symbols=XAU,XAG,XPD,XPT,XCU,NI,ZNC,ALU,LEAD&base_currency=USD';

// Function to fetch data from the API
const fetchMetalsData = async () => {
    try {
        const response = await axios.get(API_URL, {
            headers: {
                'x-api-key': API_KEY,
            },
        });
        cache = response.data; // Store response in cache
        lastFetched = Date.now(); // Record the fetch time
        console.log('Data fetched from API');
    } catch (error) {
        console.error('Error fetching data:', error.message);
    }
};

// Function to check cache validity
const isCacheValid = () => {
    if (!cache) return false; // If cache is empty, return false
    return (Date.now() - lastFetched) < 60000; // Cache is valid for 60 seconds
};

// API Route to get market data
export default async function handler(req, res) {
    if (!isCacheValid()) {
        await fetchMetalsData(); // Fetch new data if cache is invalid
    }
    res.status(200).json(cache); // Return cached data
}

// Start fetching data initially
fetchMetalsData();
setInterval(fetchMetalsData, 60000); // Refresh cache every 60 seconds

Step 5: Create a Page to Display the Data

Next, create a simple page that fetches the cached data from the API route and displays it. Open the pages/index.js file and update it as follows:

// pages/index.js
import { useEffect, useState } from 'react';

export default function Home() {
    const [metalsData, setMetalsData] = useState([]);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState('');

    const fetchMetalsData = async () => {
        try {
            const response = await fetch('/api/metals');
            if (!response.ok) throw new Error('Network response was not ok');
            const result = await response.json();
            console.log(result.data.rates)
            setMetalsData(result.data.rates);
            setLoading(false);
        } catch (error) {
            setError('Failed to fetch data');
            setLoading(false);
        }
    };

    useEffect(() => {
        fetchMetalsData();
    }, []);

    if (loading) return <p>Loading...</p>;
    if (error) return <p>{error}</p>;

    return (
        <div>
            <h1>Metals Market Data</h1>
            <table>
                <thead>
                    <tr>
                        <th>Symbol</th>
                        <th>Open (USD)</th>
                        <th>High (USD)</th>
                        <th>Low (USD)</th>
                        <th>Prev (USD)</th>
                        <th>current (USD)</th>
                    </tr>
                </thead>
                <tbody>
                    {Object.keys(metalsData).map((metalKey) => {
                      console.log(metalKey)
                      return (
                        <tr key={metalKey}>
                            <td>{metalKey}</td>
                            <td>{metalsData[metalKey].open}</td>
                            <td>{metalsData[metalKey].high}</td>
                            <td>{metalsData[metalKey].low}</td>
                            <td>{metalsData[metalKey].prev}</td>
                            <td>{metalsData[metalKey].current}</td>
                        </tr>
                      )
                    })}
                </tbody>
            </table>
            <style jsx>{`
                table {
                    margin: 20px auto;
                    border-collapse: collapse;
                    width: 80%;
                }
                th, td {
                    border: 1px solid #ccc;
                    padding: 10px;
                }
                th {
                    background-color: #f2f2f2;
                }
            `}</style>
        </div>
    );
}

Step 6: Run Your Next.js Application

Now you can run your Next.js application by executing the following command in your terminal:

npm run dev

Your Next.js application should now be running on http://localhost:3000. You should see a loading message initially, and once the data is fetched from your API route, it will display a table with the symbols and prices of the metals.

Conclusion

Congratulations! You've built a Next.js application that fetches market data from an external API, caches it locally, and serves it through an API endpoint. The cache refreshes every minute, allowing efficient data retrieval without excessive API calls. You can further enhance this application by adding features like error handling, logging, or user-friendly design.