git.iko.soy/purestack-dev/purescript-purestack-server
on master help sign in
.
commit94d927cfead73d3242e9415a34575b21a5413c03 authoriko <mail@iko.soy> dateTue 3 Jun 2025, 17:23 (1 year ago) parent30b25db
3 files changed+86−89
index.js+58−50 spago.dhall+1 src/PureStack/Router.purs+27−39
index.js+58−50
@@ -1411,31 +1411,49 @@
14111411 var runAPI = function(dict) {
14121412 return dict.runAPI;
14131413 };
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+ };
14141444 var run3 = function() {
14151445 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+ };
14171452 };
14181453 };
14191454 var parseRoute = function(dict) {
14201455 return dict.parseRoute;
14211456 };
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− });
14391457 var runAPICons = function(dictParseRoute) {
14401458 var parseRoute1 = parseRoute(dictParseRoute);
14411459 return function() {
@@ -1448,46 +1466,22 @@
14481466 return function() {
14491467 return {
14501468 runAPI: function(handlers) {
1451− return function(req) {
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 [];
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− }();
1469+ return function(v) {
1470+ return function(req) {
14751471 var v1 = parseRoute1({
1476− path: path2,
1477− verb: verb1
1472+ path: v.path,
1473+ verb: v.verb
14781474 });
14791475 if (v1 instanceof Nothing) {
1480− return runAPI1($$delete4($$Proxy.value)(handlers))(req);
1476+ return runAPI1($$delete4($$Proxy.value)(handlers))(v)(req);
14811477 }
14821478 ;
14831479 if (v1 instanceof Just) {
14841480 return v1.value0(get2($$Proxy.value)(handlers))(req);
14851481 }
14861482 ;
1487− throw new Error("Failed pattern match at PureStack.Router (line 166, column 9 - line 168, column 63): " + [v1.constructor.name]);
1488− }
1489− ;
1490− throw new Error("Failed pattern match at PureStack.Router (line 157, column 5 - line 168, column 63): " + [v.constructor.name]);
1483+ throw new Error("Failed pattern match at PureStack.Router (line 150, column 5 - line 152, column 59): " + [v1.constructor.name]);
1484+ };
14911485 };
14921486 }
14931487 };
@@ -1497,6 +1491,20 @@
14971491 };
14981492 };
14991493 };
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+ };
15001508 var assert = function(dictApplicative) {
15011509 var pure22 = pure(dictApplicative);
15021510 return function(dictPlus) {
@@ -1510,7 +1518,7 @@
15101518 return empty4;
15111519 }
15121520 ;
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]);
15141522 };
15151523 };
15161524 };
spago.dhall+1
@@ -9,6 +9,7 @@
99 , "maybe"
1010 , "prelude"
1111 , "record"
12+ , "run"
1213 , "tuples"
1314 , "typelevel-prelude"
1415 , "unsafe-coerce"
src/PureStack/Router.purs+27−39
@@ -27,6 +27,7 @@ import Data.Argonaut (class EncodeJson, Json, encodeJson)
2727import Data.Array as Array
2828import Data.Maybe (Maybe(..))
2929import Data.Symbol (class IsSymbol, reflectSymbol)
30+import Data.URL (URL)
3031import Data.URL as URL
3132import Data.Unit (Unit)
3233import Effect (Effect)
@@ -36,42 +37,22 @@ import Prim.RowList (class RowToList)
3637import Prim.RowList as RowList
3738import Record as Record
3839import 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
4440
4541data GET :: Type -> Type
4642data GET resp
4743
48−instance Verb (GET resp) resp where
49− verb = "GET"
50−
5144data POST :: Type -> Type -> Type
5245data POST req resp
5346
54−instance Verb (POST req resp) resp where
55− verb = "POST"
56−
5747data PUT :: Type -> Type -> Type
5848data PUT req resp
5949
60−instance Verb (PUT req resp) resp where
61− verb = "PUT"
62−
6350data DELETE :: Type -> Type -> Type
6451data DELETE req resp
6552
66−instance Verb (DELETE req resp) (req -> Effect resp) where
67− verb = "DELETE"
68−
6953data PATCH :: Type -> Type -> Type
7054data PATCH req resp
7155
72−instance Verb (PATCH req resp) (req -> Effect resp) where
73− verb = "PATCH"
74−
7556data Slash :: forall k1 k2. k1 -> k2 -> Type
7657data Slash x y
7758
@@ -79,6 +60,18 @@ infixr 6 type Slash as /
7960
8061type Route = { path :: Array String, verb :: String }
8162
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+
8275class ParseRoute :: forall k. k -> Type -> Constraint
8376class ParseRoute route handler | route -> handler where
8477 parseRoute :: Route -> Maybe (handler -> Request -> Effect Response)
@@ -139,10 +132,10 @@ assert true = pure unit
139132assert false = empty
140133
141134class RunAPI row list handlers | row -> handlers where
142− runAPI :: Record handlers -> Request -> Effect Response
135+ runAPI :: Record handlers -> Route -> Request -> Effect Response
143136
144137instance RunAPI row RowList.Nil () where
145− runAPI _ _ = pure notFound
138+ runAPI _ _ _ = pure notFound
146139
147140instance
148141 ( ParseRoute t handler
@@ -153,19 +146,10 @@ instance
153146 , Row.Lacks field restHandlers
154147 ) =>
155148 RunAPI row (RowList.Cons field t rest) handlers where
156− runAPI handlers req = do
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
167− Nothing -> runAPI @row @rest @restHandlers (Record.delete (Proxy @field) handlers) req
168− Just f -> f (Record.get (Proxy @field) handlers) req
149+ runAPI handlers route@{ path, verb } req =
150+ case parseRoute @t { path, verb } of
151+ Nothing -> runAPI @row @rest @restHandlers (Record.delete (Proxy @field) handlers) route req
152+ Just f -> f (Record.get (Proxy @field) handlers) req
169153
170154notFound :: Response
171155notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [] }
@@ -173,8 +157,12 @@ notFound = Response.string "" { status: 404, statusText: "Not Found", headers: [
173157internalServerError :: Response
174158internalServerError = Response.string "" { status: 500, statusText: "Internal Server Error", headers: [] }
175159
176−run :: forall @row list handlers. RowToList row list => RunAPI row list handlers => Record handlers -> Request -> Effect Response
177−run = runAPI @row @list @handlers
178−
179−---------------------------------------------------------------------------------------------------
160+run
161+ :: forall @row list handlers
162+ . RowToList row list
163+ => RunAPI row list handlers
164+ => Record handlers
165+ -> Request
166+ -> Effect Response
167+run handlers req = runAPI @row @list @handlers handlers (routeFromRequest req) req
180168