1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE TypeOperators #-}
9import Data.Aeson (ToJSON)
10import Data.Proxy (Proxy (Proxy))
11import Data.Text (Text)
12import GHC.Generics (Generic)
13import Network.Wai.Handler.Warp (run)
14import Servant.API ((:<|>) ((:<|>)), (:>), BasicAuth,
16import Servant.API.BasicAuth (BasicAuthData (BasicAuthData))
17import Servant.Server (BasicAuthCheck (BasicAuthCheck),
18 BasicAuthResult( Authorized
21 Context ((:.), EmptyContext), Server,
24-- | let's define some types that our API returns.
26-- | private data that needs protection
27newtype PrivateData = PrivateData { ssshhh :: Text }
28 deriving (Eq, Show, Generic)
30instance ToJSON PrivateData
32-- | public data that anyone can use.
33newtype PublicData = PublicData { somedata :: Text }
34 deriving (Eq, Show, Generic)
36instance ToJSON PublicData
38-- | A user we'll grab from the database when we authenticate someone
39newtype User = User { userName :: Text }
42-- | a type to wrap our public api
43type PublicAPI = Get '[JSON] [PublicData]
45-- | a type to wrap our private api
46type PrivateAPI = Get '[JSON] PrivateData
49type API = "public" :> PublicAPI
50 :<|> "private" :> BasicAuth "foo-realm" User :> PrivateAPI
52-- | a value holding a proxy of our API type
56-- | 'BasicAuthCheck' holds the handler we'll use to verify a username and password.
57authCheck :: BasicAuthCheck User
59 let check (BasicAuthData username password) =
60 if username == "servant" && password == "server"
61 then return (Authorized (User "servant"))
62 else return Unauthorized
63 in BasicAuthCheck check
65-- | We need to supply our handlers with the right Context. In this case,
66-- Basic Authentication requires a Context Entry with the 'BasicAuthCheck' value
67-- tagged with "foo-tag" This context is then supplied to 'server' and threaded
68-- to the BasicAuth HasServer handlers.
69serverContext :: Context (BasicAuthCheck User ': '[])
70serverContext = authCheck :. EmptyContext
72-- | an implementation of our server. Here is where we pass all the handlers to our endpoints.
73-- In particular, for the BasicAuth protected handler, we need to supply a function
74-- that takes 'User' as an argument.
77 let publicAPIHandler = return [PublicData "foo", PublicData "bar"]
78 privateAPIHandler (user :: User) = return (PrivateData (userName user))
79 in publicAPIHandler :<|> privateAPIHandler
83main = run 8080 (serveWithContext api serverContext server)
87$ curl -XGET localhost:8080/public
88[{"somedata":"foo"},{"somedata":"bar"}
90$ curl -iXGET localhost:8080/private
91HTTP/1.1 401 Unauthorized
92transfer-encoding: chunked
93Date: Thu, 07 Jan 2016 22:36:38 GMT
95WWW-Authenticate: Basic realm="foo-realm"
97$ curl -iXGET localhost:8080/private -H "Authorization: Basic c2VydmFudDpzZXJ2ZXI="
99transfer-encoding: chunked
100Date: Thu, 07 Jan 2016 22:37:58 GMT
102Content-Type: application/json
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list