Warp: Adding .and(warp::body::json()) causes CORS to stop being allowed

Created on 20 Jun 2020  路  7Comments  路  Source: seanmonstar/warp

I'm putting together an API with warp, and I'm trying to make it so that certain data can be requested cross-origin via POST. However, as soon as I add .and(warp::body::json()) to the filter, CORS stops working. I am testing CORS by going to http://example.com and issuing fetch() calls with http://127.0.0.1:8081 as URL from JavaScript via Firefox' developer tools. It may be me doing something wrong here, but should that be the case I don't understand what it might be.

Code snippet where CORS does not work even though I imagine it should:
not-working.zip

Code snippet where CORS does work as I imagine it should:
working.zip

Most helpful comment

Try adding this header to fetch:

fetch("http://127.0.0.1:8081/apples", {
  method: "POST",
  body: JSON.stringify({num: 25}),
  headers: {"Content-type": "application/json; charset=UTF-8"}
})

All 7 comments

I can confirm this, having the same issue.

Oh you just need to tell cors to allow the content-type header, because we are using the json body, like this:

let cors = warp::cors()
        .allow_methods(&[Method::POST])
        .allow_header("content-type");

If you get this error in the browser console:

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

That's just because the response data wasn't json, but the request did work.

Oh you just need to tell cors to allow the content-type header, because we are using the json body, like this:

let cors = warp::cors()
        .allow_methods(&[Method::POST])
        .allow_header("content-type");

Could you apply this to the code in not-working.zip and re-send it? I tried doing it like you proposed here but the result stays the same.

This is the code I ran:

fetch("http://127.0.0.1:8081/apples", {method: "POST", body: JSON.stringify({num: 25})})

I ran it in the browser's development tools on http://example.com

Try adding this header to fetch:

fetch("http://127.0.0.1:8081/apples", {
  method: "POST",
  body: JSON.stringify({num: 25}),
  headers: {"Content-type": "application/json; charset=UTF-8"}
})

Try adding this header to fetch:

fetch("http://127.0.0.1:8081/apples", {
  method: "POST",
  body: JSON.stringify({num: 25}),
  headers: {"Content-type": "application/json; charset=UTF-8"}
})

That did the trick! Thank you. I'm thinking it might be worth noting something about CORS and headers in the documentation though as I (and seemingly 3 other people) also seem to have ran into this, but I'm not sure how this would be formulated. Not only that, but I would argue this is inconsistent with how the API works in general, as at least in some other cases it is only required that you to specify what's allowed as a way to disallow others (such as with allow_origin(), see https://github.com/seanmonstar/warp/issues/614).

Question is then whether to let that be a separate issue or convert this one.

Nice, that was a little tricky for me as well. I'm not sure about documentation either, maybe a adding a example to the repo would be enough.

I was running into this while trying to hit a warp endpoint defined like this:

let cors = warp::cors()
        .allow_any_origin()
        .allow_headers(vec!["content-type"])
        .allow_methods(&[warp::http::Method::GET, warp::http::Method::POST]);

warp::path!("v1" / "redacted")
        .and(warp::get())
        .and(warp::body::json())
        .and_then(handlers::get_redacted_v1_handler)
        .with(warp::log("routes"))
        .with(cors)
        .recover(error::recover);

While using axios like this:

    const URL = `${process.env.BACKEND_URL}/v1/redacted`;

    return axios
        .request({
            method: "GET",
            url: URL,
        })
        .then(response => {
            console.log(`< ${response.status} GET ${URL}`);
        });

Changing warp::get() to warp::post() and axios method: "GET" to "POST" had no change... but then changing the axios side to the following fixed my issue.

return axios
        .request({
            method: "POST",
            url: URL,
            data: {
                'myjsonkey': "myjsonstring",
            },
            headers: {
                "Content-type": "application/json; charset=UTF-8",
            },
        })

I'm not quite sure where the issue is as hitting my warp endpoint from Postman was working fine. But I very specifically had to do the above. Even omitting the data:{ } section of my axios request causes CORS issues, where instead I'd expect a 400 with: Request body deserialize error: EOF while parsing a value at line 1 column 0

Was this page helpful?
0 / 5 - 0 ratings

Related issues

seanmonstar picture seanmonstar  路  8Comments

silvioprog picture silvioprog  路  3Comments

nerdrew picture nerdrew  路  4Comments

kamalmarhubi picture kamalmarhubi  路  5Comments

hamptokr picture hamptokr  路  4Comments