1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE DefaultSignatures #-}
3 {-# LANGUAGE DeriveFunctor #-}
4 {-# LANGUAGE StrictData #-}
5 module Symantic.HTTP.API where
8 import Data.Eq (Eq(..))
9 import Data.Functor (Functor)
10 import Data.Kind (Constraint)
11 import Data.Ord (Ord(..))
12 import Data.String (String)
13 import Data.Text (Text)
14 import Prelude (and, pure)
15 import Text.Show (Show(..))
16 import qualified Data.ByteString as BS
17 import qualified Network.HTTP.Types as HTTP
30 ) => HTTP_API (repr:: * -> * -> *)
34 (<.>) :: repr a b -> repr b c -> repr a c; infixl 4 <.>
35 -- (.>) :: repr x y -> repr a c -> repr a c; infixl 4 .>
40 type AltMerge repr :: * -> * -> *
41 (<!>) :: repr a b -> repr c d -> repr (a:!:c) (AltMerge repr b d); infixl 3 <!>
43 (<!>) :: repr a k -> repr b k -> repr (a:!:b) k; infixl 3 <!>
44 -- try :: repr k k -> repr k k
45 -- option :: k -> repr k k -> repr k k
48 -- Like '(,)' but 'infixl'.
49 -- Used to get alternative commands from a 'Client'
50 -- or to supply alternative handlers to a 'Server'.
51 data (:!:) a b = a:!:b
55 -- | Mainly useful to write a combinator which is a specialization of another,
56 -- by calling it instead of rewriting its logic.
57 -- Because type @a@ is asked by a 'Client' but given to a 'Server',
58 -- both @a->b@ and @b->a@ are used. This is reminiscent of a 'Profunctor'.
59 -- Hence the names 'Pro' and 'dimap'.
61 dimap :: (a -> b) -> (b -> a) -> repr (a -> k) k -> repr (b -> k) k
63 -- * Class 'HTTP_Path'
64 class HTTP_Path repr where
65 type PathConstraint repr a :: Constraint
66 type PathConstraint repr a = ()
67 segment :: Segment -> repr k k
69 PathConstraint repr a =>
70 Name -> repr (a -> k) k
71 captureAll :: repr ([Segment] -> k) k
73 -- | Convenient wrapper of 'segment'.
74 (</>) :: Cat repr => HTTP_Path repr => Segment -> repr a b -> repr a b
75 (</>) n = (segment n <.>); infixr 5 </>
77 -- | Like |capture'| but with the type variable 'a' first instead or 'repr'
78 -- so it can be passed using 'TypeApplications' without adding a '@_' for 'repr'.
82 PathConstraint repr a =>
83 Name -> repr (a -> k) k
85 {-# INLINE capture #-}
91 -- * Class 'HTTP_Header'
92 class HTTP_Header repr where
93 header :: HTTP.HeaderName -> repr (HeaderValue -> k) k
95 type HeaderValue = BS.ByteString
97 -- * Class 'HTTP_Body'
98 class HTTP_Body repr where
99 type BodyArg repr :: * -> [*] -> *
100 type BodyConstraint repr a (ts::[*]) :: Constraint
101 type BodyConstraint repr a ts = ()
103 forall a (ts::[*]) k.
104 BodyConstraint repr a ts =>
105 repr (BodyArg repr a ts -> k) k
107 -- | Like |body'| but with the type variables 'a' and 'ts' first instead or 'repr'
108 -- so it can be passed using 'TypeApplications' withs adding a '@_' for 'repr'.
112 BodyConstraint repr a ts =>
113 repr (BodyArg repr a ts -> k) k
117 -- * Class 'HTTP_Query'
118 class HTTP_Query repr where
119 type QueryConstraint repr a :: Constraint
120 type QueryConstraint repr a = ()
122 QueryConstraint repr a =>
123 QueryName -> repr ([a] -> k) k
125 QueryConstraint repr Bool =>
126 QueryName -> repr (Bool -> k) k
129 QueryConstraint repr Bool =>
130 QueryName -> repr (Bool -> k) k
131 queryFlag n = dimap and pure (queryParams' n)
132 type QueryName = BS.ByteString
133 type QueryValue = BS.ByteString
138 QueryConstraint repr a =>
139 QueryName -> repr ([a] -> k) k
140 queryParams = queryParams'
141 {-# INLINE queryParams #-}
143 -- * Class 'HTTP_BasicAuth'
144 -- | <https://tools.ietf.org/html/rfc2617#section-2 Basic Access Authentication>
145 class HTTP_BasicAuth repr where
146 type BasicAuthConstraint repr a :: Constraint
147 type BasicAuthConstraint repr a = ()
148 type BasicAuthArgs repr a k :: *
150 BasicAuthConstraint repr a =>
151 BasicAuthRealm -> repr (BasicAuthArgs repr a k) k
155 HTTP_BasicAuth repr =>
156 BasicAuthConstraint repr a =>
158 repr (BasicAuthArgs repr a k) k
159 basicAuth = basicAuth' @repr @a @k
160 {-# INLINE basicAuth #-}
162 -- ** Type 'BasicAuth'
164 = BasicAuth_Authorized usr
165 | BasicAuth_BadPassword
166 | BasicAuth_NoSuchUser
167 | BasicAuth_Unauthorized
168 deriving (Eq, Show, Functor)
170 type BasicAuthRealm = Text
171 type BasicAuthUser = Text
172 type BasicAuthPass = Text
174 -- * Class 'HTTP_Version'
175 class HTTP_Version repr where
176 version :: HTTP.HttpVersion -> repr k k
178 -- * Class 'HTTP_Status'
179 class HTTP_Status repr where
180 status :: StatusIs -> repr (HTTP.Status -> k) k
182 -- ** Type 'StatusIs'
184 = StatusIsInformational
186 | StatusIsRedirection
187 | StatusIsClientError
188 | StatusIsServerError
189 | StatusIs HTTP.Status
190 deriving (Eq, Ord, Show)
191 statusIs :: StatusIs -> (HTTP.Status -> Bool)
193 StatusIsInformational -> HTTP.statusIsInformational
194 StatusIsSuccessful -> HTTP.statusIsSuccessful
195 StatusIsRedirection -> HTTP.statusIsRedirection
196 StatusIsClientError -> HTTP.statusIsClientError
197 StatusIsServerError -> HTTP.statusIsServerError
198 StatusIs x -> \y -> HTTP.statusCode x == HTTP.statusCode y
200 -- * Class 'HTTP_Response'
201 class HTTP_Response repr where
202 type ResponseConstraint repr a (ts::[*]) :: Constraint
203 type ResponseConstraint repr a ts = ()
204 type ResponseArgs repr a (ts::[*]) :: *
205 type Response repr :: *
207 ResponseConstraint repr a ts =>
209 repr (ResponseArgs repr a ts)
212 -- | Wrap 'response' by giving it the corresponding 'HTTP.Method',
213 -- and put the type variables 'a' then 'ts' first instead or 'repr'
214 -- so they can be passed using 'TypeApplications'
215 -- without adding a |@_| for 'repr'.
216 get,head,put,post,delete,trace,connect,options,patch ::
218 HTTP_Response repr =>
219 ResponseConstraint repr a ts =>
220 repr (ResponseArgs repr a ts)
222 get = response @repr @a @ts HTTP.methodGet
223 head = response @repr @a @ts HTTP.methodHead
224 put = response @repr @a @ts HTTP.methodPut
225 post = response @repr @a @ts HTTP.methodPost
226 delete = response @repr @a @ts HTTP.methodDelete
227 trace = response @repr @a @ts HTTP.methodTrace
228 connect = response @repr @a @ts HTTP.methodConnect
229 options = response @repr @a @ts HTTP.methodOptions
230 patch = response @repr @a @ts HTTP.methodPatch
235 {-# INLINE delete #-}
237 {-# INLINE connect #-}
238 {-# INLINE options #-}