I want to make an API call from my backend server running express.js. I expect when I visit http://localhost:3004/api/weather?city=[cityName]
, I should see the json response from openweathermap.org.
Instead, I get the message "unknown endpoint"
from my middleware. Thats the terminal output from the server:
Time: 2024-09-08T08:02:14.510Z
Method: GET
Path: /api/weather
Query: { city: 'zagreb' }
Headers: {
host: 'localhost:3004',
connection: 'keep-alive',
pragma: 'no-cache',
'cache-control': 'no-cache',
'sec-ch-ua': '"Chromium";v="128", "Not;A=Brand";v="24", "Google Chrome";v="128"',
'sec-ch-ua-mobile': '?0',
'sec-ch-ua-platform': '"macOS"',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36',
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
'sec-fetch-site': 'none',
'sec-fetch-mode': 'navigate',
'sec-fetch-user': '?1',
'sec-fetch-dest': 'document',
'accept-encoding': 'gzip, deflate, br, zstd',
'accept-language': 'en,de-DE;q=0.9,de;q=0.8,fr-FR;q=0.7,fr;q=0.6,en-US;q=0.5,hr;q=0.4,nl;q=0.3',
cookie: 'Webstorm-8aead92d=3b86ad4a-0728-412a-9b16-792fba3736a2'
}
Body: {}
IP: ::1
Here is my code for the Route:
require('dotenv').config()
const weatherRouter = require('express').Router()
const axios = require('axios')
const apiKey = process.env.API_KEY
weatherRouter.get('/api/weather', async (req, res, next) => {
const { city } = req.query
if (!city) {
return res.status(400).json({ error: 'City must be provided' });
}
try {
console.log(`Fetching weather data for ${city}`);
const response = await axios.get(`http://api.openweathermap.org/geo/1.0/direct?q=${city}&limit=5&appid=${apiKey}`);
res.json(response.data);
} catch (error) {
res.status(500).json({ error: 'Failed to fetch weather data' });
}
next()
})
module.exports = weatherRouter
The final goal is, that I make the request from a form from the frontend running react.js. This currently does not work either. That is the code I wrote on the frontend to link it to with be backend:
import axios from 'axios'
const baseUrl = '/api/weather'
const getWeatherData = async city => {
const response = await axios.get(`${baseUrl}?city=${city}`)
return response.data
}
export default { getWeatherData }
Can anyone tell me what I am doing wrong? Here is the code from app.js where I mount the routes:
const config = require('./utils/config')
const express = require('express')
require('express-async-errors')
const app = express()
const cors = require('cors')
const citiesRouter = require('./controllers/cities')
const weathersRouter = require('./controllers/weathers')
/* const usersRouter = require('./controllers/users')
const loginRouter = require('./controllers/login') */
const middleware = require('./utils/middleware')
const logger = require('./utils/logger')
const mongoose = require('mongoose')
mongoose.set('strictQuery', false)
logger.info('connecting to', config.MONGODB_URI)
mongoose.connect(config.MONGODB_URI)
.then(() => {
logger.info('connected to MongoDB')
})
.catch((error) => {
logger.error('error connection to MongoDB:', error.message)
})
app.use(cors())
app.use(express.static('dist'))
app.use(express.json())
app.use(middleware.requestLogger)
app.use(middleware.tokenExtractor)
app.use('/api/cities', citiesRouter)
app.use('/api/weather', weathersRouter)
app.use(middleware.unknownEndpoint)
app.use(middleware.errorHandler)
module.exports = app
Here is the code from vite.config.js:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
proxy: {
"/api": {
target: "http://localhost:3004",
changeOrigin: true,
},
},
})
Here is a screenshot when making a get request from the frontend:
Here is a screenshot after removing the proxy in vite.config.js and setting baseURL to http://localhost:3004/api/weather:
Full example BE and FE:
// index.js
const express = require('express');
const weatherRouter = require('./routes/weatherRouter'); // Import the weatherRouter
const app = express();
const port = 3004;
// Middleware to parse JSON
app.use(express.json());
// Use the weatherRouter for '/api/weather' routes
app.use('/api/weather', weatherRouter);
// Root route
app.get('/', (req, res) => {
res.send('Welcome to the Express App!');
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
weatherRouter
// routes/weatherRoutter.js
const express = require('express');
const router = express.Router();
// A simple weather route
router.get('/', (req, res) => {
res.json({
location: 'New York',
temperature: '22°C',
condition: 'Sunny',
});
});
module.exports = router;
Frontend code:
vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': {
target: 'http://localhost:3004',
changeOrigin: true,
},
},
},
});
api.js
import axios from 'axios';
const axiosClient = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || '',
});
const getWeatherData = async (city) => {
const response = await axiosClient.get('/api/weather', {
params: {
city,
},
});
return response.data;
};
export default { getWeatherData };
App.jsx
import { useEffect } from 'react';
import './App.css';
import api from './api';
function App() {
useEffect(() => {
api.getWeatherData('New York').then((data) => console.log(data));
}, []);
return <div>Test</div>;
}
export default App;