New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CORS support #45
Comments
Hi, I have CORS configured within Nginx config (see CORS on Nginx). I am not sure there is currently any simple way to add CORS directly into Haskell server code, but maybe |
I'm looking for something in Haskell, yes, but thank you for linking the nginx docs. I want to be able to see the swagger docs without running nginx in dev. |
@bitemyapp ok, so for Here's a working example (tested with LTS 5.16): {-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeOperators #-}
module Main where
import Servant
import Data.Text
import Data.Swagger
import Servant.Swagger
import Network.Wai.Middleware.Cors (simpleCors)
import Network.Wai.Handler.Warp (run)
import Network.Wai.Middleware.RequestLogger (logStdoutDev)
type HelloAPI = "hello" :> Get '[JSON] Text
type SwaggerAPI = "swagger.json" :> Get '[JSON] Swagger
type TestAPI = SwaggerAPI :<|> HelloAPI
server :: Server TestAPI
server = return (toSwagger (Proxy :: Proxy HelloAPI))
:<|> return "Hello, world!"
main :: IO ()
main = run 8000 $ simpleCors $ logStdoutDev $ serve (Proxy :: Proxy TestAPI) server It appears that at work we have something else demanding more complicated CORS configuration (in particular we have to allow more headers). |
if you do a more complicated request, such as https://github.com/leshow/elm-tut/blob/master/app/server/src/Api.hs#L17 does it still work for you? simpleCors was enough to get regular GET requests working from localhost:x to localhost:y , but anything more complicated like a PUT or POST with a request body, seemed to fail for me. You can try the simple app in the link |
@leshow sorry for the delay in response.
So you can't use From here you can either use a different -- | Allow Content-Type header with values other then allowed by simpleCors.
corsWithContentType :: Middleware
corsWithContentType = cors (const $ Just policy)
where
policy = simpleCorsResourcePolicy
{ corsRequestHeaders = ["Content-Type"] } I have tested it with this code (I also added |
@bitemyapp @leshow Can this issue be closed? |
I have added the custom content type like you mentioned above but I still can't get POST/PUT requests resolved from the browser console errors from browser:
and logged from the backend
I have updated the project with the minimal changes to make it work (haven't added swagger yet, just wanted to see if i could reproduce the issue) https://github.com/leshow/elm-tut When you tested it, did you try sending a application/json request from the browser? |
@leshow I have tested with this tool: http://test-cors.org I have also tried sending requests from the Swagger UI (running on http://localhost:8080/ui/). How are you sending your requests from the browser? var createCORSRequest = function(method, url) {
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
// Most browsers.
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined") {
// IE8 & IE9
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
// CORS not supported.
xhr = null;
}
return xhr;
};
var url = 'http://localhost:8080/api/player/0';
var method = 'POST';
var xhr = createCORSRequest(method, url);
xhr.onload = function() {
// Success code goes here.
};
xhr.onerror = function() {
// Error code goes here.
};
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.setRequestHeader('Accept', 'application/json');
xhr.send(); |
PUT or POST will cause the browser to send a preflight OPTIONS request to see if cors is supported. If you look in the chrome or firefox dev tools for the network requests, you should see that preflight OPTIONS before the post, if it isn't there, then the issue isn't being recreated properly. |
I believe it is relevant to this: |
@leshow yes, I understand preflight requests, and Since it works for me (in the browser) I am trying to figure out, what JavaScript code are you testing CORS with to recreate the problem on my side. |
I wrote the frontend in elm, you can see it here: saveUrl : PlayerId -> String
saveUrl playerId =
"http://localhost:4000/api/player/" ++ (toString playerId)
saveTask : Player -> Task.Task Http.Error Player
saveTask player =
let
body =
playerEncoded player
|> Encode.encode 0
|> Http.string
config =
{ verb = "PUT"
, headers = [ ( "Content-Type", "application/json" ) ]
, url = saveUrl player.id
, body = body
}
in
Http.send Http.defaultSettings config
|> Http.fromJson playerDecode |
@leshow just to be sure that app responds to
|
Does that work for you as well? |
yes, it appears to work for all except: > ~ curl -i -X OPTIONS http://localhost:4000/api/player/1 -H 'Origin: 127.0.0.1' -H 'Access-Control-Request-Method: PUT'
HTTP/1.1 400 Bad Request
Transfer-Encoding: chunked
Date: Fri, 22 Jul 2016 01:59:27 GMT
Server: Warp/3.2.6
Content-Type: text/html; charset-utf-8
Method requested in Access-Control-Request-Method of CORS request is not supported; requested: PUT; supported are GET, HEAD, POST.%
|
switching to POST in the app is a workaround I can live with. It appears this cors middleware only supports get/post/head like the console log says |
Aha, so it does work for myCors :: Middleware
myCors = cors (const $ Just policy)
where
policy = simpleCorsResourcePolicy
{ corsRequestHeaders = ["Content-Type"]
, corsMethods = "PUT" : simpleMethods } |
thanks so much for your help, sorry it took me a while to get this, feel free to close the issue |
@leshow you're welcome! Sorry again for the delay in response to your original question! |
👍 Good to go here as well, thank you very much @fizruk 🐻 |
I get a compiler error. Snippet:
Error:
How do I pass |
@i-schuetz seems like you forgot to enable |
Thanks @fizruk! (sorry for using this thread for this newbie question, it was just convenient) |
Feature/suspend team
@fizruk, thanks, this post really helps. Can this information be included in servant documentation? It seems fairly common that people want to include enabling |
I can't get the demo to work with a recent version of Swagger because it seems to want fine-grained CORS. AFAICT,
OPTIONS
isn't even supported in Servant. How do I make this work?The text was updated successfully, but these errors were encountered: