W
Wasp-lang17mo ago
DimAss

API CORS error

Hi, I'm trying to fetch a PUT endpoint, but it throws a CORS error in the console (testing locally). Frontend is on localhost:3000, backend is on localhost:3001 What am I doing wrong?
No description
No description
No description
22 Replies
DimAss
DimAss17mo ago
Request headers:
No description
DimAss
DimAss17mo ago
I also tried to manually set CORS headers for that endpoint, but it didn't help
No description
DimAss
DimAss17mo ago
Interesting, this only happens when I'm logged in using Google Auth... No CORS errors when there is no auth session, tried with Chrome and Firefox
miho
miho17mo ago
If you are looking to update a product, a more natural mechanism in Wasp is using actions. Wasp has an RPC setup between backend and client, so you don't have to mess around too much with setting up APIs by hand. The RPC has queries and actions. With queries you get your products for example, and with actions you make changes. Here's the part of the docs that discusses that: https://wasp-lang.dev/docs/language/features#queries-and-actions-aka-operations For example, you would declare in your Wasp file:
action updateProduct {
fn: import { updateProduct } from "@server/actions.js",
entities: [Product]
}
action updateProduct {
fn: import { updateProduct } from "@server/actions.js",
entities: [Product]
}
and then write the implementation in actions.ts/js
export const updateProduct = (args, context) => {
return context.entities.Product.update({ where: { id: args.id }, ...}
}
export const updateProduct = (args, context) => {
return context.entities.Product.update({ where: { id: args.id }, ...}
}
And then use it on the frontend
import updateProduct from "@wasp/actions/updateProduct"
...
import updateProduct from "@wasp/actions/updateProduct"
...
miho
miho17mo ago
APIs on the other hand were more envisioned as escape hatches for when you really need more control. For example, a webhook for Stripe payments being one of the use cases. The APIs don't come with all of the middleware setup to prevent collisons. So you need to set them up with ideally apiNamespace and a middleware function.
DimAss
DimAss17mo ago
Hi @miho I haven't found a way to use HTTP verbs with actions, all action requests are done via POST. Is there a way to change that?
miho
miho17mo ago
That's the way the current RPC functions, do you have a use case where you need the PUT verb? 🙂 Maybe something for us to change in the future 🤷‍♂️
DimAss
DimAss17mo ago
Well, for example I'm using react-admin and it expects GET/POST/PUT/DELETE to do entity manipulations @miho so no default middlewares are applied to api endpoints?
miho
miho17mo ago
Hmm that's really interesting! We will play with react-admin ourselves and see what's the best path forward. In the meantime, if you really want to make your api work, please consider doing this: https://wasp-lang.dev/docs/guides/middleware-customization#3-customize-per-path-middleware
Middleware Customization | Wasp
Wasp comes with a minimal set of useful Express middleware in every application. While this is good for most users, we realize some may wish to add, modify, or remove some of these choices both globally, or on a per-api/path basis.
miho
miho17mo ago
@miho so no default middlewares are applied to api endpoints?
They are applied to the put but not options keyword which breaks the CORS behaviour (we are looking into fixing this on the framework level) If you define /api -> apiNamespace and then define the middleware there to apply, it should work 🙂 Let me write you an example, gimme a minute
DimAss
DimAss17mo ago
I managed to fix it by copying the default middleware and adding it to apiNamespace, thank you! However, this is an extremely unpredictable behaviour, so it might be a good idea to mention the lack of middlewares for API endpoints in docs 🙂
No description
No description
miho
miho17mo ago
Nice! You could have just returned the input middleware you received 😄
import { MiddlewareConfigFn } from "@wasp/middleware"
export const apiMiddleware: MiddlewareConfigFn = (config) => {
return config;
}
import { MiddlewareConfigFn } from "@wasp/middleware"
export const apiMiddleware: MiddlewareConfigFn = (config) => {
return config;
}
Why this works as well, the config already contains all the default middleware (one of them is CORS)
DimAss
DimAss17mo ago
Aha, got it 🙂
miho
miho17mo ago
Thank you for the patience and testing Wasp, let us know if you stumble upon any other issues. We will explore how to better support react-admin out of the box and similar needs for using Wasp as just the server 🙂
DimAss
DimAss17mo ago
Btw this doc example is kinda misleading as well, since that header setup does not really work properly
No description
DimAss
DimAss17mo ago
Sure, thank you for your help!
martinsos
martinsos17mo ago
This might be interesting: there is a piece in react-admin docs that says how to support RPC like Wasp has, by adding custom methods to your data provider, it also mentions useQuery -> so I would say it is probably very close / exactly what you need, check it out: https://marmelab.com/react-admin/Actions.html#calling-custom-methods .
martinsos
martinsos17mo ago
Thanks @DimAss for feedback so far, I create two issues to capture what was said here: https://github.com/wasp-lang/wasp/issues/1303 https://github.com/wasp-lang/wasp/issues/1304 so we will be able to work in the future on improving Wasp for these use cases!
fustuk.
fustuk.3mo ago
@miho I stumble on the same issue currently, this still isnt working for me
api fooBar {
fn: import { fooBar } from "@src/api",
entities: [Video,User],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@src/api",
httpRoute: (POST, "/video")
}
api fooBar {
fn: import { fooBar } from "@src/api",
entities: [Video,User],
auth: true,
middlewareConfigFn: import { apiMiddleware } from "@src/api",
httpRoute: (POST, "/video")
}
Even if I set cors like so
export const apiMiddleware: MiddlewareConfigFn = (middlewareConfig) => {
return middlewareConfig.set('cors', cors());
};
export const apiMiddleware: MiddlewareConfigFn = (middlewareConfig) => {
return middlewareConfig.set('cors', cors());
};
await api.post(/video) I get CORS If I use fetch it works properly but im currently passing my user id as query param until I resolve this
miho
miho3mo ago
The difference is that the user above used apiMiddleware declaration and not middlewareConfigFn inside of the api declaration. https://wasp-lang.dev/docs/advanced/middleware-config#3-customize-per-path-middleware
api fooBar {
fn: import { fooBar } from "@src/api",
entities: [Video,User],
auth: true,
httpRoute: (POST, "/video")
}

apiMiddleware something {
middlewareConfigFn: import { apiMiddleware } from "@src/api",
}
api fooBar {
fn: import { fooBar } from "@src/api",
entities: [Video,User],
auth: true,
httpRoute: (POST, "/video")
}

apiMiddleware something {
middlewareConfigFn: import { apiMiddleware } from "@src/api",
}
The difference is that then the CORS is set for both POST and OPTIONS request methods and not just POST.
Configuring Middleware | Wasp
Wasp comes with a minimal set of useful Express middleware in every application. While this is good for most users, we realize some may wish to add, modify, or remove some of these choices both globally, or on a per-api/path basis.
fustuk.
fustuk.3mo ago
I think I got it thank you !
Sven
Sven2mo ago
yo man how did u fix it evenutally got it to work no idea why tbh
Want results from more Discord servers?
Add your server