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:
2
Answers
Updated:
Yes, correct I missed that from your post.
Fix your baseURL in case you use vite proxy and also better use env var for production.
/api
2 times because/api
=http://localhost:3004
from vite proxy and also your endpoint url starts with/api
. Without proxy baseUrl should behttp://localhost:3004
in case you’ll decide to remove it.And also remove
next()
in your request handler on BE. You already send response from request handler for all cases but because of next() call some of your middlewares that goes next afterapp.use('/api/weather', weathersRouter)
try to send response again. That’s why you are gettingCannot set headers after they are sent to the client
.In the router, change route from:
to
as you’re already using that route when mounting the router here: