How to send server request to back-end relay and return API data to front-end

I am building a simple weather app. I am a front-end developer who has barely touched anything related to the back-end. In the process of building my weather app I wanted to use an API. I encountered an issue, my API key was public for anyone to see. I did some research on how to hide it and found out you need to create a back-end server relay to (I assume) take a request from the front end, use the API to generate the data on the back-end, then return that data to the front end.

Because I have very little experience with the back-end, I have attempted to do all this myself but am confused.

My goal is to have the client enter a location in the search bar of the application, for example, ‘Paris’, then send that to the back-end server (Node.js), convert ‘Paris’ to coordinates using the geocoding API, send the longitude and latitude to the weather API which will use that data to return an object of weather data for that region.

So far I have managed to:

  1. get the server to return the data I need but I do not know how to send this data to the front end.
  2. I can only use the server to generate the data if I replace the ${INSERT_LOCATION_HERE} to a location name manually because I don’t know how to send for example ‘Paris’ from the front-end to the server.

Here is a smaller version of the application with all the code:

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" type="text/css" href="style.css">
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=NTR&display=swap" rel="stylesheet">
    <title>Weather App</title>
</head>
<body>
    <section class="search-bar">
        <div class="container">
            <span class="input-container">
                <input class="input" type="text" placeholder="Enter a city">
                <button class="set">SET</button>
            </span>
        </div>
    </section>
    <section class="weather-information">
        <div class="success-container">
            <div class="inner-container">
                <div class="weather-details">
                    <header class="temperature">-°</header>
                    <p class="feels-like-temperature">Feels like: -°</p>
                    <p class="weather">Weather: -</p>
                    <p class="smaller-line-height humidity">Humidity: -%</p>
                    <p class="smaller-line-height wind-speed">Wind Speed: -m/s</p>
                </div>
            </div>
        </div>
    </section>
    <script src="script.js"></script>
</body>
</html>

CSS

/* Code to remove all element default styling */

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    font-family: 'NTR', sans-serif;
    font-size: 20px;
}

button,
button:hover {
    background: transparent;
    box-shadow: 0px 0px 0px transparent;
    text-shadow: 0px 0px 0px transparent;
}

button {
    -webkit-tap-highlight-color: transparent;
    border: 0px solid transparent;
}

button:active,
button:focus
.submit-button,
input:focus, textarea:focus, select:focus {
    outline: none;
}
  
button:active,
.wrapper-for-each-form-section input,
.wrapper-for-each-form-section textarea,
.submit-button {
    border: none;
}

/* All Devices */

.search-bar {
    font-size: 0.75rem;
    width: 100%;
    height: 5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    top: 25px;
    letter-spacing: 1px;
}

.search-bar .container {
    height: 100%;
    width: 75%;
    border-bottom: 2px solid #d6d6d6;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

.search-bar .container .input-container {
    height: 70%;
    width: 100%;
    display: flex;
    align-items: center;
}

.search-bar .container .input-container input {
    font-size: 1.5rem;
    border: none;
    width: 70%;
}

.search-bar .container .input-container button {
    width: 30%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    color: #adadad;
    cursor: pointer;
}

.weather-information {
    height: 20rem;
    width: 100%;
    position: relative;
    top: 60px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.weather-information .success-container {
    height: 100%;
    width: 75%;
    border-radius: 1rem;
    background: #f6f5fa;
    box-shadow: 0 10px 10px 0 rgb(0 0 0 / 16%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    opacity: 100%;
    position: absolute;
    z-index: 10;
}

.weather-information .success-container .inner-container {
    height: 85%;
    width: 80%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}

.weather-information .success-container .inner-container .image-container {
    display: flex;
    width: 100%;
    height: 35%;
    align-items: center;
    justify-content: center;
}

.weather-information .success-container .inner-container .image-container img {
    height: 100%;
}

.weather-information .success-container .inner-container .weather-details {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: space-between;
    width: 100%;
    height: 65%;
}

.weather-information .success-container .inner-container .weather-details header {
    font-size: 3.5rem;
    line-height: 3.5rem;
}

.weather-information .success-container .inner-container .weather-details p:nth-child(2),
.weather-information .success-container .inner-container .weather-details p:nth-child(3) {
    font-size: 1.5rem;
    line-height: 1.5rem;
    font-weight: 400;
}

.weather-information .success-container .inner-container .weather-details .smaller-line-height {
    font-size: 1rem;
    line-height: 1rem;
    font-weight: 500;
}

JavaScript (client)

const inputField = document.querySelector('.input');
const setButton = document.querySelector('.set');

// All elements for weather details when API call is successful:
const weatherDetailsContainer = document.querySelector('.success-container');
const temperature = document.querySelector('.temperature');
const feelsLiketemperature = document.querySelector('.feels-like-temperature');
const weather = document.querySelector('.weather');
const humidity = document.querySelector('.humidity');
const windSpeed = document.querySelector('.wind-speed');

setButton.addEventListener('click', () => {
    // insert code to send data to server
})

JavaScript (Server)

// These import necessary modules and set some initial variables
require("dotenv").config();
const express = require("express");
const fetch = require("node-fetch");
const rateLimit = require("express-rate-limit");
var cors = require("cors");
const app = express();
const port = 3000;
const axios = require("axios");

const limiter = rateLimit({
  windowMs: 1000, // 1 second
  max: 1, // limit each IP to 1 requests per windowMs
});

//  apply to all requests
app.use(limiter);

// Allow CORS from any origin
app.use(cors());

// Routes

app.get("/", (req, res) => res.send("Hello World!"));

app.get("/api/search", async (req, res) => {
  try {
    const coordAPI = await fetch(`https://api.openweathermap.org/geo/1.0/direct?q=${INSERT_LOCATION_HERE}limit=1&appid=${process.env.API_KEY}`);

    const coordAPIResponse = await coordAPI.json();

    const coordAPIResults = {
      lat: coordAPIResponse[0].lat,
      lon: coordAPIResponse[0].lon
    }

    const weatherDataAPI = await fetch(`https://api.openweathermap.org/data/2.5/weather?lat=${coordAPIResults.lat}&lon=${coordAPIResults.lon}&appid=${process.env.API_KEY}&units=metric`)

    weatherDataAPIResponse = await weatherDataAPI.json();

    res.send({
      success: true,
      results: weatherDataAPIResponse,
    });
  } catch (err) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
});

// This spins up our sever and generates logs for us to use.
// Any console.log statements you use in node for debugging will show up in your
// terminal, not in the browser console!
app.listen(port, () => console.log(`Example app listening on port ${port}!`));