packages feed

servant-options (empty) → 0.1.0.0

raw patch · 5 files changed

+152/−0 lines, 5 filesdep +basedep +bytestringdep +http-typessetup-changed

Dependencies added: base, bytestring, http-types, servant-foreign, servant-server, text, wai

Files

+ LICENSE view
@@ -0,0 +1,21 @@+Copyright 2017 Lyndon Maydwell++Permission is hereby granted, free of charge, to any person obtaining a copy of+this software and associated documentation files (the "Software"), to deal in+the Software without restriction, including without limitation the rights to+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies+of the Software, and to permit persons to whom the Software is furnished to do+so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.++
+ README.md view
@@ -0,0 +1,37 @@+## Servant-Options++This library provides a middleware that returns `HTTP OPTIONS` responses for+valid application routes defined by your (Proxy :: Proxy api).+It is especially useful when trying to write an API that can be used+in a cross-origin capacity, as browsers will send "pre-flight" checks+by requesting OPTIONS for routes that are about to be called.++Before:++![](https://github.com/sordina/servant-options/blob/master/images/before.png?raw=true)++After:++![](https://github.com/sordina/servant-options/blob/master/images/after.png?raw=true)++Usage:++    module MyApp where++    import App+    import Servant+    import Network.Wai.Middleware.Cors+    import Network.Wai.Middleware.Servant.Options++    app :: Application+    app = logStdoutDev+        $ cors (const $ Just policy)+        $ provideOptions apiProxy+        $ serve apiProxy apiServer+      where+      policy = simpleCorsResourcePolicy+               { corsRequestHeaders = [ "content-type" ] }++## See Also++* <https://github.com/haskell-servant/servant/issues/278>
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ servant-options.cabal view
@@ -0,0 +1,35 @@+-- This file has been generated from package.yaml by hpack version 0.15.0.+--+-- see: https://github.com/sol/hpack++name:           servant-options+version:        0.1.0.0+synopsis:       Provide responses to OPTIONS requests for Servant applications.+description:    Provide responses to OPTIONS requests for Servant applications.+category:       Web+homepage:       https://github.com/sordina/servant-options+author:         Lyndon Maydwell+maintainer:     maydwell@gmail.com+copyright:      2017 Lyndon Maydwell+license:        MIT+license-file:   LICENSE+build-type:     Simple+cabal-version:  >= 1.10++extra-source-files:+    README.md++library+  hs-source-dirs:+      src+  build-depends:+      base >= 4.7 && < 5+    , servant-server+    , servant-foreign+    , wai+    , bytestring+    , text+    , http-types+  exposed-modules:+      Network.Wai.Middleware.Servant.Options+  default-language: Haskell2010
+ src/Network/Wai/Middleware/Servant/Options.hs view
@@ -0,0 +1,57 @@+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- A middleware to respond to Options requests for a servant app+-- very helpful when trying to deal with pre-flight CORS requests.+--+module Network.Wai.Middleware.Servant.Options (provideOptions) where++import Servant+import Servant.Foreign+import Network.Wai+import Data.Text hiding (null, zipWith, length)+import Network.HTTP.Types.Method+import Data.Maybe+import Data.List (nub)+import Network.HTTP.Types+import qualified Data.ByteString as B++provideOptions :: (GenerateList NoContent (Foreign NoContent api), HasForeign NoTypes NoContent api)+               => Proxy api -> Middleware+provideOptions apiproxy app req cb+  | rmeth == "OPTIONS" = optional cb prior pinfo mlist+  | otherwise          = prior+  where+  rmeth = requestMethod req :: Method+  pinfo = pathInfo      req :: [ Text ]+  mlist = listFromAPI (Proxy :: Proxy NoTypes) (Proxy :: Proxy NoContent) apiproxy+  prior = app req cb++optional :: (Response -> r) -> r -> [Text] -> [Req NoContent] -> r+optional cb prior ts rs+  | null methods = prior+  | otherwise    = cb (buildResponse methods)+  where+  methods = mapMaybe (getMethod ts) rs++getMethod :: [Text] -> Req NoContent -> Maybe Method+getMethod rs ps+  | sameLength && matchingSegments = Just (_reqMethod ps)+  | otherwise                      = Nothing+  where+  pattern          = _path $ _reqUrl ps+  sameLength       = length rs == length pattern+  matchingSegments = and $ zipWith matchSegment rs pattern++matchSegment :: Text -> Segment NoContent -> Bool+matchSegment a (Segment (Static (PathSegment b)) ) | a /= b = False+matchSegment _ _                                            = True++buildResponse :: [Method] -> Response+buildResponse ms = responseBuilder s h mempty+  where+  s = Status 200 "OK"+  m = B.intercalate ", " ("OPTIONS" : nub ms)+  h = [ ("Allow", m) ]+