git.iko.soy/purestack-dev/purescript-purestack-server
on master help sign in
.
94d927ciko
index.js+58−50
@@ -1411,31 +1411,49 @@
1411 var runAPI = function(dict) {
1411 var runAPI = function(dict) {
1412 return dict.runAPI;
1412 return dict.runAPI;
1413 };
1413 };
1414+ var routeFromRequest = function(req) {
1415+ return {
1416+ verb: method(req),
1417+ path: function() {
1418+ var v = fromString2(url(req));
1419+ if (v instanceof Nothing) {
1420+ return [];
1421+ }
1422+ ;
1423+ if (v instanceof Just) {
1424+ var v1 = path(v.value0);
1425+ if (v1 instanceof PathEmpty) {
1426+ return [];
1427+ }
1428+ ;
1429+ if (v1 instanceof PathAbsolute) {
1430+ return v1.value0;
1431+ }
1432+ ;
1433+ if (v1 instanceof PathRelative) {
1434+ return v1.value0;
1435+ }
1436+ ;
1437+ throw new Error("Failed pattern match at PureStack.Router (line 68, column 19 - line 71, column 32): " + [v1.constructor.name]);
1438+ }
1439+ ;
1440+ throw new Error("Failed pattern match at PureStack.Router (line 66, column 11 - line 71, column 32): " + [v.constructor.name]);
1441+ }()
1442+ };
1443+ };
1414 var run3 = function() {
1444 var run3 = function() {
1415 return function(dictRunAPI) {
1445 return function(dictRunAPI) {
1416− return runAPI(dictRunAPI);
1446+ var runAPI1 = runAPI(dictRunAPI);
1447+ return function(handlers) {
1448+ return function(req) {
1449+ return runAPI1(handlers)(routeFromRequest(req))(req);
1450+ };
1451+ };
1417 };
1452 };
1418 };
1453 };
1419 var parseRoute = function(dict) {
1454 var parseRoute = function(dict) {
1420 return dict.parseRoute;
1455 return dict.parseRoute;
1421 };
1456 };
1422− var notFound = /* @__PURE__ */ string("")({
1423− status: 404,
1424− statusText: "Not Found",
1425− headers: []
1426− });
1427− var runAPINilRow = {
1428− runAPI: function(v) {
1429− return function(v1) {
1430− return pure2(notFound);
1431− };
1432− }
1433− };
1434− var internalServerError = /* @__PURE__ */ string("")({
1435− status: 500,
1436− statusText: "Internal Server Error",
1437− headers: []
1438− });
1439 var runAPICons = function(dictParseRoute) {
1457 var runAPICons = function(dictParseRoute) {
1440 var parseRoute1 = parseRoute(dictParseRoute);
1458 var parseRoute1 = parseRoute(dictParseRoute);
1441 return function() {
1459 return function() {
@@ -1448,46 +1466,22 @@
1448 return function() {
1466 return function() {
1449 return {
1467 return {
1450 runAPI: function(handlers) {
1468 runAPI: function(handlers) {
1451− return function(req) {
1469+ return function(v) {
1452− var v = fromString2(url(req));
1453− if (v instanceof Nothing) {
1454− return pure2(internalServerError);
1455− }
1456− ;
1457− if (v instanceof Just) {
1458− var verb1 = method(req);
1459− var path2 = function() {
1460− var v12 = path(v.value0);
1461− if (v12 instanceof PathEmpty) {
1462− return [];
1470+ return function(req) {
1463− }
1464− ;
1465− if (v12 instanceof PathAbsolute) {
1466− return v12.value0;
1467− }
1468− ;
1469− if (v12 instanceof PathRelative) {
1470− return v12.value0;
1471− }
1472− ;
1473− throw new Error("Failed pattern match at PureStack.Router (line 161, column 18 - line 164, column 36): " + [v12.constructor.name]);
1474− }();
1475 var v1 = parseRoute1({
1471 var v1 = parseRoute1({
1476− path: path2,
1472+ path: v.path,
1477− verb: verb1
1473+ verb: v.verb
1478 });
1474 });
1479 if (v1 instanceof Nothing) {
1475 if (v1 instanceof Nothing) {
1480− return runAPI1($$delete4($$Proxy.value)(handlers))(req);
1476+ return runAPI1($$delete4($$Proxy.value)(handlers))(v)(req);
1481 }
1477 }
1482 ;
1478 ;
1483 if (v1 instanceof Just) {
1479 if (v1 instanceof Just) {
1484 return v1.value0(get2($$Proxy.value)(handlers))(req);
1480 return v1.value0(get2($$Proxy.value)(handlers))(req);
1485 }
1481 }
1486 ;
1482 ;
1487− throw new Error("Failed pattern match at PureStack.Router (line 166, column 9 - line 168, column 63): " + [v1.constructor.name]);
1483+ throw new Error("Failed pattern match at PureStack.Router (line 150, column 5 - line 152, column 59): " + [v1.constructor.name]);
1488− }
1484+ };
1489− ;
1490− throw new Error("Failed pattern match at PureStack.Router (line 157, column 5 - line 168, column 63): " + [v.constructor.name]);
1491 };
1485 };
1492 }
1486 }
1493 };
1487 };
@@ -1497,6 +1491,20 @@
1497 };
1491 };
1498 };
1492 };
1499 };
1493 };
1494+ var notFound = /* @__PURE__ */ string("")({
1495+ status: 404,
1496+ statusText: "Not Found",
1497+ headers: []
1498+ });
1499+ var runAPINilRow = {
1500+ runAPI: function(v) {
1501+ return function(v1) {
1502+ return function(v2) {
1503+ return pure2(notFound);
1504+ };
1505+ };
1506+ }
1507+ };
1500 var assert = function(dictApplicative) {
1508 var assert = function(dictApplicative) {
1501 var pure22 = pure(dictApplicative);
1509 var pure22 = pure(dictApplicative);
1502 return function(dictPlus) {
1510 return function(dictPlus) {
@@ -1510,7 +1518,7 @@
1510 return empty4;
1518 return empty4;
1511 }
1519 }
1512 ;
1520 ;
1513− throw new Error("Failed pattern match at PureStack.Router (line 137, column 1 - line 137, column 65): " + [v.constructor.name]);
1521+ throw new Error("Failed pattern match at PureStack.Router (line 130, column 1 - line 130, column 65): " + [v.constructor.name]);
1514 };
1522 };
1515 };
1523 };
1516 };
1524 };
spago.dhall+1
@@ -9,6 +9,7 @@
9 , "maybe"
9 , "maybe"
10 , "prelude"
10 , "prelude"
11 , "record"
11 , "record"
12+ , "run"
12 , "tuples"
13 , "tuples"
13 , "typelevel-prelude"
14 , "typelevel-prelude"
14 , "unsafe-coerce"
15 , "unsafe-coerce"
src/PureStack/Router.purs+27−39
@@ -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)
30+import Data.URL (URL)
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)
40−
41−class Verb :: Type -> Type -> Constraint
42−class Verb t resp | t -> resp where
43− verb :: String
44
40
45data GET :: Type -> Type
41data GET :: Type -> Type
46data GET resp
42data GET resp
47
43
48−instance Verb (GET resp) resp where
49− verb = "GET"
50−
51data POST :: Type -> Type -> Type
44data POST :: Type -> Type -> Type
52data POST req resp
45data POST req resp
53
46
54−instance Verb (POST req resp) resp where
55− verb = "POST"
56−
57data PUT :: Type -> Type -> Type
47data PUT :: Type -> Type -> Type
58data PUT req resp
48data PUT req resp
59
49
60−instance Verb (PUT req resp) resp where
61− verb = "PUT"
62−
63data DELETE :: Type -> Type -> Type
50data DELETE :: Type -> Type -> Type
64data DELETE req resp
51data DELETE req resp
65
52
66−instance Verb (DELETE req resp) (req -> Effect resp) where
67− verb = "DELETE"
68−
69data PATCH :: Type -> Type -> Type
53data PATCH :: Type -> Type -> Type
70data PATCH req resp
54data PATCH req resp
71
55
72−instance Verb (PATCH req resp) (req -> Effect resp) where
73− verb = "PATCH"
74−
75data Slash :: forall k1 k2. k1 -> k2 -> Type
56data Slash :: forall k1 k2. k1 -> k2 -> Type
76data Slash x y
57data Slash x y
77
58
@@ -79,6 +60,18 @@ infixr 6 type Slash as /
79
60
80type Route = { path :: Array String, verb :: String }
61type Route = { path :: Array String, verb :: String }
81
62
63+routeFromRequest :: Request -> Route
64+routeFromRequest req =
65+ { verb: Request.method req
66+ , path: case URL.fromString (Request.url req) of
67+ Nothing -> []
68+ Just url -> case URL.path url of
69+ URL.PathEmpty -> []
70+ URL.PathAbsolute p -> p
71+ URL.PathRelative p -> p
72+
73+ }
74+
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
140
133
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
143
136
144instance RunAPI row RowList.Nil () where
137instance RunAPI row RowList.Nil () where
145− runAPI _ _ = pure notFound
138+ runAPI _ _ _ = pure notFound
146
139
147instance
140instance
148 ( ParseRoute t handler
141 ( ParseRoute t handler
@@ -153,19 +146,10 @@ instance
153 , Row.Lacks field restHandlers
146 , Row.Lacks field restHandlers
154 ) =>
147 ) =>
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
159− Just url -> do
160− let
161− path = case URL.path url of
162− URL.PathEmpty -> []
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
169
153
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: [] }
175
159
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
164+ => Record handlers
165+ -> Request
166+ -> Effect Response
177−run = runAPI @row @list @handlers
167+run handlers req = runAPI @row @list @handlers handlers (routeFromRequest req) req
178−
179−---------------------------------------------------------------------------------------------------
180
168