@@ -20,6 +20,10 @@ module PureStack.Server
20 , serveQuery
20 , serveQuery
21 , class ParsePathPiece
21 , class ParsePathPiece
22 , parsePathPiece
22 , parsePathPiece
25import Prelude
29import Prelude
@@ -49,6 +53,8 @@ import Foreign.Object as Object
49import Prim.Row as Row
53import Prim.Row as Row
50import Prim.RowList (class RowToList, RowList)
54import Prim.RowList (class RowToList, RowList)
51import Prim.RowList as RowList
55import Prim.RowList as RowList
56+import PureStack.Cookie (Cookie)
57+import PureStack.Cookie as Cookie
52import Record as Record
58import Record as Record
53import Record.Builder (Builder)
59import Record.Builder (Builder)
54import Record.Builder as Builder
60import Record.Builder as Builder
@@ -103,31 +109,23 @@ else instance (ServeRoute rest handler m, ParsePathPiece t) => ServeRoute (t / r
103 t <- parsePathPiece @t h
109 t <- parsePathPiece @t h
104 serveRoute @rest route { path = tail } <#> (\f nt handler req -> f nt (handler t) req)
110 serveRoute @rest route { path = tail } <#> (\f nt handler req -> f nt (handler t) req)
106−else instance ToResponse resp => ServeRoute (GET resp) (m resp) m where
112+else instance MethodName (meth Unit Unit) => ServeRoute (meth Unit Unit) (m Unit) m where
107 serveRoute { path, verb } = do
113 serveRoute { path, verb } = do
108− assert $ verb == "GET"
114+ assert $ verb == methodName @(meth Unit Unit)
110− pure $ \(Nt nt) handler _req -> do
112− pure $ toResponse resp
114−else instance ServeRoute (POST Unit Unit) (m Unit) m where
115− serveRoute { path, verb } = do
116− assert $ verb == "POST"
117 assert $ path == []
115 assert $ path == []
118 pure $ \(Nt nt) handler _req -> do
116 pure $ \(Nt nt) handler _req -> do
119 nt handler
117 nt handler
120 pure $ ok
118 pure $ ok
121−else instance (ToResponse resp) => ServeRoute (POST Unit resp) (m resp) m where
119+else instance (ToResponse resp, MethodName (meth Unit resp)) => ServeRoute (meth Unit resp) (m resp) m where
122 serveRoute { path, verb } = do
120 serveRoute { path, verb } = do
123− assert $ verb == "POST"
121+ assert $ verb == methodName @(meth Unit resp)
124 assert $ path == []
122 assert $ path == []
125 pure $ \(Nt nt) handler _req -> do
123 pure $ \(Nt nt) handler _req -> do
126 resp <- nt handler
124 resp <- nt handler
127 pure $ toResponse resp
125 pure $ toResponse resp
128−else instance (FromRequest req) => ServeRoute (POST resp Unit) (req -> m Unit) m where
126+else instance (FromRequest req, MethodName (meth resp Unit)) => ServeRoute (meth resp Unit) (req -> m Unit) m where
129 serveRoute { path, verb } = do
127 serveRoute { path, verb } = do
130− assert $ verb == "POST"
128+ assert $ verb == methodName @(meth resp Unit)
131 assert $ path == []
129 assert $ path == []
132 pure $ \(Nt nt) handler req -> do
130 pure $ \(Nt nt) handler req -> do
133 liftAff (fromRequest req) >>= case _ of
131 liftAff (fromRequest req) >>= case _ of
@@ -135,114 +133,9 @@ else instance (FromRequest req) => ServeRoute (POST resp Unit) (req -> m Unit) m
135 Just r -> do
133 Just r -> do
136 nt $ handler r
134 nt $ handler r
137 pure $ ok
135 pure $ ok
138−else instance (FromRequest req, ToResponse resp) => ServeRoute (POST req resp) (req -> m resp) m where
136+else instance (FromRequest req, ToResponse resp, MethodName (meth req resp)) => ServeRoute (meth req resp) (req -> m resp) m where
139 serveRoute { path, verb } = do
137 serveRoute { path, verb } = do
140− assert $ verb == "POST"
138+ assert $ verb == methodName @(meth req resp)
142− pure $ \(Nt nt) handler req -> do
143− liftAff (fromRequest req) >>= case _ of
144− Nothing -> pure $ badRequest
146− resp <- nt $ handler r
147− pure $ toResponse resp
149−else instance ServeRoute (DELETE Unit Unit) (m Unit) m where
150− serveRoute { path, verb } = do
151− assert $ verb == "DELETE"
153− pure $ \(Nt nt) handler _req -> do
156−else instance (ToResponse resp) => ServeRoute (DELETE Unit resp) (m resp) m where
157− serveRoute { path, verb } = do
158− assert $ verb == "DELETE"
160− pure $ \(Nt nt) handler _req -> do
162− pure $ toResponse resp
163−else instance (FromRequest req) => ServeRoute (DELETE resp Unit) (req -> m Unit) m where
164− serveRoute { path, verb } = do
165− assert $ verb == "DELETE"
167− pure $ \(Nt nt) handler req -> do
168− liftAff (fromRequest req) >>= case _ of
169− Nothing -> pure $ badRequest
173−else instance (FromRequest req, ToResponse resp) => ServeRoute (DELETE req resp) (req -> m resp) m where
174− serveRoute { path, verb } = do
175− assert $ verb == "DELETE"
177− pure $ \(Nt nt) handler req -> do
178− liftAff (fromRequest req) >>= case _ of
179− Nothing -> pure $ badRequest
181− resp <- nt $ handler r
182− pure $ toResponse resp
184−else instance ServeRoute (PUT Unit Unit) (m Unit) m where
185− serveRoute { path, verb } = do
186− assert $ verb == "PUT"
188− pure $ \(Nt nt) handler _req -> do
191−else instance (ToResponse resp) => ServeRoute (PUT Unit resp) (m resp) m where
192− serveRoute { path, verb } = do
193− assert $ verb == "PUT"
195− pure $ \(Nt nt) handler _req -> do
197− pure $ toResponse resp
198−else instance (FromRequest req) => ServeRoute (PUT resp Unit) (req -> m Unit) m where
199− serveRoute { path, verb } = do
200− assert $ verb == "PUT"
202− pure $ \(Nt nt) handler req -> do
203− liftAff (fromRequest req) >>= case _ of
204− Nothing -> pure $ badRequest
208−else instance (FromRequest req, ToResponse resp) => ServeRoute (PUT req resp) (req -> m resp) m where
209− serveRoute { path, verb } = do
210− assert $ verb == "PUT"
212− pure $ \(Nt nt) handler req -> do
213− liftAff (fromRequest req) >>= case _ of
214− Nothing -> pure $ badRequest
216− resp <- nt $ handler r
217− pure $ toResponse resp
219−else instance ServeRoute (PATCH Unit Unit) (m Unit) m where
220− serveRoute { path, verb } = do
221− assert $ verb == "PATCH"
223− pure $ \(Nt nt) handler _req -> do
226−else instance (ToResponse resp) => ServeRoute (PATCH Unit resp) (m resp) m where
227− serveRoute { path, verb } = do
228− assert $ verb == "PATCH"
230− pure $ \(Nt nt) handler _req -> do
232− pure $ toResponse resp
233−else instance (FromRequest req) => ServeRoute (PATCH resp Unit) (req -> m Unit) m where
234− serveRoute { path, verb } = do
235− assert $ verb == "PATCH"
237− pure $ \(Nt nt) handler req -> do
238− liftAff (fromRequest req) >>= case _ of
239− Nothing -> pure $ badRequest
243−else instance (FromRequest req, ToResponse resp) => ServeRoute (PATCH req resp) (req -> m resp) m where
244− serveRoute { path, verb } = do
245− assert $ verb == "PATCH"
246 assert $ path == []
139 assert $ path == []
247 pure $ \(Nt nt) handler req -> do
140 pure $ \(Nt nt) handler req -> do
248 liftAff (fromRequest req) >>= case _ of
141 liftAff (fromRequest req) >>= case _ of
@@ -342,6 +235,84 @@ instance DecodeJson (Record row) => FromRequest (Record row) where
342instance FromRequest Request where
235instance FromRequest Request where
343 fromRequest req = pure $ Just req
236 fromRequest req = pure $ Just req
238+instance FromRequest Unit where
239+ fromRequest _ = pure $ Just unit
245+ FromRequest (Headers (Object header) req) where
246+ fromRequest req = do
247+ r <- fromRequest req
249+ headers <- traverse fromHeader (Request.headers req)
251+ pure $ Headers headers r'
254+ ( RowToList headers headersList
256+ , FromHeaders headers headersList
258+ FromRequest (Headers (Record headers) req) where
259+ fromRequest req = do
260+ r <- fromRequest req
262+ headers <- fromHeaders @headers @headersList (Request.headers req)
264+ pure $ Headers (Builder.buildFromScratch headers) r'
266+class FromHeader t where
267+ fromHeader :: String -> Maybe t
269+instance FromHeader Cookie where
270+ fromHeader = Cookie.parse >>> case _ of
274+instance FromHeader String where
277+instance FromHeader Int where
278+ fromHeader = Int.fromString
280+class FromHeaders :: Row Type -> RowList Type -> Constraint
281+class FromHeaders row list | list -> row where
282+ fromHeaders :: Object String -> Maybe (Builder {} (Record row))
284+instance FromHeaders () RowList.Nil where
285+ fromHeaders _ = Just $ identity
290+ , FromHeaders tail rest
291+ , Row.Cons field (Maybe t) tail row
292+ , Row.Lacks field tail
294+ FromHeaders row (RowList.Cons field (Maybe t) rest) where
295+ fromHeaders headers = do
296+ r <- fromHeaders @tail @rest headers
297+ case Object.lookup (reflectSymbol @field Proxy) headers of
298+ Nothing -> pure $ Builder.insert (Proxy @field) Nothing <<< r
301+ pure $ Builder.insert (Proxy @field) (Just v) <<< r
306+ , FromHeaders tail rest
307+ , Row.Cons field t tail row
308+ , Row.Lacks field tail
310+ FromHeaders row (RowList.Cons field t rest) where
311+ fromHeaders headers = do
312+ t <- Object.lookup (reflectSymbol @field Proxy) headers >>= fromHeader
313+ r <- fromHeaders @tail @rest headers
314+ pure $ Builder.insert (Proxy @field) t <<< r
345class ParsePathPiece t where
316class ParsePathPiece t where
346 parsePathPiece :: String -> Maybe t
317 parsePathPiece :: String -> Maybe t
@@ -406,10 +377,10 @@ run
406 . RowToList row list
377 . RowToList row list
407 => ServeAPI row list handlers m
378 => ServeAPI row list handlers m
408 => (forall x. m x -> Server x)
379 => (forall x. m x -> Server x)
409− -> Record handlers
380+ -> { handlers :: Record handlers }
410 -> Request
381 -> Request
411 -> Aff Bun.Response.Response
382 -> Aff Bun.Response.Response
412−run nt handlers req = do
383+run nt { handlers } req = do
413 Response { body, headers, status, statusText } <-
384 Response { body, headers, status, statusText } <-
414 map (either identity identity) $ runExceptT $ serveAPI @row @list @handlers (Nt nt) handlers (routeFromRequest req) req
385 map (either identity identity) $ runExceptT $ serveAPI @row @list @handlers (Nt nt) handlers (routeFromRequest req) req
415 let opts = { headers, status, statusText }
386 let opts = { headers, status, statusText }