@@ -27,6 +27,7 @@ import Data.Argonaut (class EncodeJson, Json, encodeJson)
27import Data.Array as Array
27import Data.Array as Array
28import Data.Maybe (Maybe(..))
28import Data.Maybe (Maybe(..))
29import Data.Symbol (class IsSymbol, reflectSymbol)
29import Data.Symbol (class IsSymbol, reflectSymbol)
30import Data.URL as URL
31import Data.URL as URL
31import Data.Unit (Unit)
32import Data.Unit (Unit)
32import Effect (Effect)
33import Effect (Effect)
@@ -36,42 +37,22 @@ import Prim.RowList (class RowToList)
36import Prim.RowList as RowList
37import Prim.RowList as RowList
37import Record as Record
38import Record as Record
38import Type.Prelude (Proxy(..))
39import Type.Prelude (Proxy(..))
39−import Unsafe.Coerce (unsafeCoerce)
41−class Verb :: Type -> Type -> Constraint
42−class Verb t resp | t -> resp where
45data GET :: Type -> Type
41data GET :: Type -> Type
46data GET resp
42data GET resp
48−instance Verb (GET resp) resp where
51data POST :: Type -> Type -> Type
44data POST :: Type -> Type -> Type
52data POST req resp
45data POST req resp
54−instance Verb (POST req resp) resp where
57data PUT :: Type -> Type -> Type
47data PUT :: Type -> Type -> Type
58data PUT req resp
48data PUT req resp
60−instance Verb (PUT req resp) resp where
63data DELETE :: Type -> Type -> Type
50data DELETE :: Type -> Type -> Type
64data DELETE req resp
51data DELETE req resp
66−instance Verb (DELETE req resp) (req -> Effect resp) where
69data PATCH :: Type -> Type -> Type
53data PATCH :: Type -> Type -> Type
70data PATCH req resp
54data PATCH req resp
72−instance Verb (PATCH req resp) (req -> Effect resp) where
75data Slash :: forall k1 k2. k1 -> k2 -> Type
56data Slash :: forall k1 k2. k1 -> k2 -> Type
76data Slash x y
57data Slash x y
@@ -79,6 +60,18 @@ infixr 6 type Slash as /
80type Route = { path :: Array String, verb :: String }
61type Route = { path :: Array String, verb :: String }
63+routeFromRequest :: Request -> Route
64+routeFromRequest req =
65+ { verb: Request.method req
66+ , path: case URL.fromString (Request.url req) of
68+ Just url -> case URL.path url of
70+ URL.PathAbsolute p -> p
71+ URL.PathRelative p -> p
82class ParseRoute :: forall k. k -> Type -> Constraint
75class ParseRoute :: forall k. k -> Type -> Constraint
83class ParseRoute route handler | route -> handler where
76class ParseRoute route handler | route -> handler where
84 parseRoute :: Route -> Maybe (handler -> Request -> Effect Response)
77 parseRoute :: Route -> Maybe (handler -> Request -> Effect Response)
@@ -139,10 +132,10 @@ assert true = pure unit
139assert false = empty
132assert false = empty
141class RunAPI row list handlers | row -> handlers where
134class RunAPI row list handlers | row -> handlers where
142− runAPI :: Record handlers -> Request -> Effect Response
135+ runAPI :: Record handlers -> Route -> Request -> Effect Response
144instance RunAPI row RowList.Nil () where
137instance RunAPI row RowList.Nil () where
145− runAPI _ _ = pure notFound
138+ runAPI _ _ _ = pure notFound
148 ( ParseRoute t handler
141 ( ParseRoute t handler
@@ -153,19 +146,10 @@ instance
153 , Row.Lacks field restHandlers
146 , Row.Lacks field restHandlers
155 RunAPI row (RowList.Cons field t rest) handlers where
148 RunAPI row (RowList.Cons field t rest) handlers where
156− runAPI handlers req = do
149+ runAPI handlers route@{ path, verb } req =
157− case URL.fromString (Request.url req) of
158− Nothing -> pure internalServerError
161− path = case URL.path url of
163− URL.PathAbsolute p -> p
164− URL.PathRelative p -> p
165− verb = Request.method req
166− case parseRoute @t { path, verb } of
150+ case parseRoute @t { path, verb } of
167− Nothing -> runAPI @row @rest @restHandlers (Record.delete (Proxy @field) handlers) req
151+ Nothing -> runAPI @row @rest @restHandlers (Record.delete (Proxy @field) handlers) route req
168− Just f -> f (Record.get (Proxy @field) handlers) req
152+ Just f -> f (Record.get (Proxy @field) handlers) req
170notFound :: Response
154notFound :: Response
171notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [] }
155notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [] }
@@ -173,8 +157,12 @@ notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [
173internalServerError :: Response
157internalServerError :: Response
174internalServerError = Response.string "" { status: 500, statusText: "Internal Server Error", headers: [] }
158internalServerError = Response.string "" { status: 500, statusText: "Internal Server Error", headers: [] }
176−run :: forall @row list handlers. RowToList row list => RunAPI row list handlers => Record handlers -> Request -> Effect Response
160+run
161+ :: forall @row list handlers
162+ . RowToList row list
163+ => RunAPI row list handlers
177−run = runAPI @row @list @handlers
167+run handlers req = runAPI @row @list @handlers handlers (routeFromRequest req) req
179−---------------------------------------------------------------------------------------------------