I am encountering an issue with Next.js that I don’t quite understand. I have a service file that I want to use to make API calls faster and more structured. However, when I call the API via this service, I get a CORS error, but everything works when I call the API directly from my component.
My apiService.ts file:
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
const apiClient = axios.create({
baseURL: 'http://localhost:4000',
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*', // Allow all origins
},
withCredentials: true,
});
// Generic function for GET requests
export const get = async <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
try {
const response: AxiosResponse<T> = await apiClient.get(url, config);
return response.data;
} catch (error) {
console.error('GET request error:', error);
throw error;
}
};
// Generic function for POST requests
export const post = async <T, R>(url: string, data: T, config?: AxiosRequestConfig): Promise<R> => {
try {
const response: AxiosResponse<R> = await apiClient.post(url, data, config);
return response.data;
} catch (error) {
console.error('POST request error:', error);
throw error;
}
};
// Generic function for PUT requests
export const put = async <T, R>(url: string, data: T, config?: AxiosRequestConfig): Promise<R> => {
try {
const response: AxiosResponse<R> = await apiClient.put(url, data, config);
return response.data;
} catch (error) {
console.error('PUT request error:', error);
throw error;
}
};
// Generic function for DELETE requests
export const deleteRequest = async <T>(url: string, config?: AxiosRequestConfig): Promise<T> => {
try {
const response: AxiosResponse<T> = await apiClient.delete(url, config);
return response.data;
} catch (error) {
console.error('DELETE request error:', error);
throw error;
}
};
In my modal component (ModalCreateExercise.tsx), I call the API like this:
'use client'
import { zodResolver } from "@hookform/resolvers/zod"
import { SubmitHandler, useForm } from "react-hook-form"
import { z } from "zod"
import axios from 'axios';
import { BaseModal } from "@/components/commun/BaseModal"
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import { createExercise, getExercises } from "@/services/exerciseService"
import { Exercise } from "@/types/exercise"
import { useEffect, useState } from "react"
import { get, post } from "@/app/services/axiosService";
const formSchema = z.object({
name: z.string().min(2, {
message: "Username must be at least 2 characters.",
}),
})
export function ModalCreateExercise() {
const [exercises, setExercises] = useState<Exercise[]>([]);
//it's working
useEffect(() => {
const fetchExercises = async () => {
try {
// Making the API call with axios directly
const response = await axios.get<Exercise[]>('http://localhost:4000/exercises');
console.log('Exercises fetched:', response.data);
} catch (error) {
console.error('Error fetching exercises:', error);
}
};
fetchExercises();
}, []);
// don't working
useEffect(() => {
const fetchExercises = async () => {
try {
const response = await get<Exercise[]>('/exercises');
console.log('Exercises fetched:', response);
} catch (error) {
console.error('Error fetching exercises:', error);
}
};
fetchExercises();
}, []);
const form = useForm<z.infer<typeof formSchema>>({
resolver: zodResolver(formSchema),
defaultValues: {
name: ""
},
})
const onSubmit = async() => {
const data: Exercise = {
userId: 1,
name: form.getValues().name,
};
try {
const newExercise = await post<typeof data, Exercise>('/exercises', data);
console.log('Exercise created:', newExercise);
} catch (error) {
console.error('Error creating exercise:', error);
}
};
return (
<BaseModal className="ml-auto" title="Créer un exercice" description="Créer un exercice pour vos étudiants" buttonTitle="Créer un exercice" saveButtonTitle="Créer">
<div>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Nom de l'exercice</FormLabel>
<FormControl>
<Input placeholder="Nom" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
</div>
</BaseModal>
)
}
My issue:
When I use the native axios method in the useEffect, everything works fine, and I can fetch the data from the API without any CORS issues. However, as soon as I try to call the API via my service with Axios, I run into a CORS problem.
The backend server (NestJS) is configured to accept CORS requests, but the issue only occurs when I call the API via the service I created. The problem seems to stem from the fact that the API is not recognizing calls coming from this service.
Here’s what I’ve tried:
I verified the CORS configuration on my NestJS server, and it seems correct.
I attempted to add Access-Control-Allow-Origin headers in my service file, but it didn’t resolve the issue.
Do you have any idea why this happens? Perhaps something related to how Axios is configured or how cookies are handled?
Thank you in advance for your help!