1 {-# LANGUAGE DefaultSignatures #-}
2 {-# LANGUAGE DeriveFunctor #-}
3 {-# LANGUAGE StrictData #-}
4 module Symantic.HTTP.API where
7 import Data.Eq (Eq(..))
8 import Data.Functor (Functor)
9 import Data.Kind (Constraint)
10 import Data.Ord (Ord(..))
11 import Data.String (String)
12 import Data.Text (Text)
13 import Prelude (and, pure)
14 import Text.Show (Show(..))
15 import qualified Data.ByteString as BS
16 import qualified Network.HTTP.Types as HTTP
29 ) => HTTP_API (repr:: * -> * -> *)
33 (<.>) :: repr a b -> repr b c -> repr a c; infixl 4 <.>
34 -- (.>) :: repr x y -> repr a c -> repr a c; infixl 4 .>
39 type AltMerge repr :: * -> * -> *
40 (<!>) :: repr a b -> repr c d -> repr (a:!:c) (AltMerge repr b d); infixl 3 <!>
42 (<!>) :: repr a k -> repr b k -> repr (a:!:b) k; infixl 3 <!>
43 -- try :: repr k k -> repr k k
44 -- option :: k -> repr k k -> repr k k
47 -- Like '(,)' but 'infixl'.
48 -- Used to get alternative commands from a 'Client'
49 -- or to supply alternative handlers to a 'Server'.
50 data (:!:) a b = a:!:b
54 -- | Mainly useful to write a combinator which is a specialization of another,
55 -- by calling it instead of rewriting its logic.
56 -- Because type @a@ is asked by a 'Client' but given to a 'Server',
57 -- both @a->b@ and @b->a@ are used. This is reminiscent of a 'Profunctor'.
58 -- Hence the names 'Pro' and 'dimap'.
60 dimap :: (a -> b) -> (b -> a) -> repr (a -> k) k -> repr (b -> k) k
62 -- * Class 'HTTP_Path'
63 class HTTP_Path repr where
64 type PathConstraint repr a :: Constraint
65 type PathConstraint repr a = ()
66 segment :: Segment -> repr k k
68 PathConstraint repr a =>
69 Name -> repr (a -> k) k
70 captureAll :: repr ([Segment] -> k) k
72 -- | Convenient wrapper of 'segment'.
73 (</>) :: Cat repr => HTTP_Path repr => Segment -> repr a b -> repr a b
74 (</>) n = (segment n <.>); infixr 5 </>
76 -- | Like |capture'| but with the type variable 'a' first instead or 'repr'
77 -- so it can be passed using 'TypeApplications' without adding a '@_' for 'repr'.
81 PathConstraint repr a =>
82 Name -> repr (a -> k) k
84 {-# INLINE capture #-}
90 -- * Class 'HTTP_Header'
91 class HTTP_Header repr where
92 header :: HTTP.HeaderName -> repr (HeaderValue -> k) k
94 type HeaderValue = BS.ByteString
96 -- * Class 'HTTP_Body'
97 class HTTP_Body repr where
98 type BodyArg repr :: * -> [*] -> *
99 type BodyConstraint repr a (ts::[*]) :: Constraint
100 type BodyConstraint repr a ts = ()
102 forall a (ts::[*]) k.
103 BodyConstraint repr a ts =>
104 repr (BodyArg repr a ts -> k) k
106 -- | Like |body'| but with the type variables 'a' and 'ts' first instead or 'repr'
107 -- so it can be passed using 'TypeApplications' withs adding a '@_' for 'repr'.
111 BodyConstraint repr a ts =>
112 repr (BodyArg repr a ts -> k) k
116 -- * Class 'HTTP_Query'
117 class HTTP_Query repr where
118 type QueryConstraint repr a :: Constraint
119 type QueryConstraint repr a = ()
121 QueryConstraint repr a =>
122 QueryName -> repr ([a] -> k) k
124 QueryConstraint repr Bool =>
125 QueryName -> repr (Bool -> k) k
128 QueryConstraint repr Bool =>
129 QueryName -> repr (Bool -> k) k
130 queryFlag n = dimap and pure (queryParams' n)
131 type QueryName = BS.ByteString
132 type QueryValue = BS.ByteString
137 QueryConstraint repr a =>
138 QueryName -> repr ([a] -> k) k
139 queryParams = queryParams'
140 {-# INLINE queryParams #-}
142 -- * Class 'HTTP_BasicAuth'
143 -- | <https://tools.ietf.org/html/rfc2617#section-2 Basic Access Authentication>
144 class HTTP_BasicAuth repr where
145 type BasicAuthConstraint repr a :: Constraint
146 type BasicAuthConstraint repr a = ()
147 type BasicAuthArgs repr a k :: *
149 BasicAuthConstraint repr a =>
150 BasicAuthRealm -> repr (BasicAuthArgs repr a k) k
154 HTTP_BasicAuth repr =>
155 BasicAuthConstraint repr a =>
157 repr (BasicAuthArgs repr a k) k
158 basicAuth = basicAuth' @repr @a @k
159 {-# INLINE basicAuth #-}
161 -- ** Type 'BasicAuth'
163 = BasicAuth_Authorized usr
164 | BasicAuth_BadPassword
165 | BasicAuth_NoSuchUser
166 | BasicAuth_Unauthorized
167 deriving (Eq, Show, Functor)
169 type BasicAuthRealm = Text
170 type BasicAuthUser = Text
171 type BasicAuthPass = Text
173 -- * Class 'HTTP_Version'
174 class HTTP_Version repr where
175 version :: HTTP.HttpVersion -> repr k k
177 -- * Class 'HTTP_Status'
178 class HTTP_Status repr where
179 status :: StatusIs -> repr (HTTP.Status -> k) k
181 -- ** Type 'StatusIs'
183 = StatusIsInformational
185 | StatusIsRedirection
186 | StatusIsClientError
187 | StatusIsServerError
188 | StatusIs HTTP.Status
189 deriving (Eq, Ord, Show)
190 statusIs :: StatusIs -> (HTTP.Status -> Bool)
192 StatusIsInformational -> HTTP.statusIsInformational
193 StatusIsSuccessful -> HTTP.statusIsSuccessful
194 StatusIsRedirection -> HTTP.statusIsRedirection
195 StatusIsClientError -> HTTP.statusIsClientError
196 StatusIsServerError -> HTTP.statusIsServerError
197 StatusIs x -> \y -> HTTP.statusCode x == HTTP.statusCode y
199 -- * Class 'HTTP_Response'
200 class HTTP_Response repr where
201 type ResponseConstraint repr a (ts::[*]) :: Constraint
202 type ResponseConstraint repr a ts = ()
203 type ResponseArgs repr a (ts::[*]) :: *
204 type Response repr :: *
206 ResponseConstraint repr a ts =>
208 repr (ResponseArgs repr a ts)
211 -- | Wrap 'response' by giving it the corresponding 'HTTP.Method',
212 -- and put the type variables 'a' then 'ts' first instead or 'repr'
213 -- so they can be passed using 'TypeApplications'
214 -- without adding a |@_| for 'repr'.
215 get,head,put,post,delete,trace,connect,options,patch ::
217 HTTP_Response repr =>
218 ResponseConstraint repr a ts =>
219 repr (ResponseArgs repr a ts)
221 get = response @repr @a @ts HTTP.methodGet
222 head = response @repr @a @ts HTTP.methodHead
223 put = response @repr @a @ts HTTP.methodPut
224 post = response @repr @a @ts HTTP.methodPost
225 delete = response @repr @a @ts HTTP.methodDelete
226 trace = response @repr @a @ts HTTP.methodTrace
227 connect = response @repr @a @ts HTTP.methodConnect
228 options = response @repr @a @ts HTTP.methodOptions
229 patch = response @repr @a @ts HTTP.methodPatch
234 {-# INLINE delete #-}
236 {-# INLINE connect #-}
237 {-# INLINE options #-}