hello, trying to figure how to parte pedestal-like nested URL format using meander, for example, go from
["v1"
["/foo"
["/baz" {:post baz-handler}]]
["/bar"
{:get bar-handler
:post post-bar}]]
to
[{:url "v1/foo/baz" :method :post :handler baz-handler}
{:url "v1/bar" :method :get :handler bar-handler}
{:url "v1/bar" :method :post :handler post-bar}]I guess I gotta use cata, but not sure how
(m/rewrite '["v1"
["/foo"
["/baz" {:post baz-handler}]]
["/bar" {:get bar-handler :post post-bar}]]
(m/with [%1 (m/map-of !methods !handlers)
%2 [!paths . (m/or %2 %1) ...]]
%2)
[{:url !paths :method !methods :handler !handlers} ...])
often with is simpler than cata
but now I see that it is not quite so, because the paths have been concatet
cool, that almost solves, the missing part is accumulating the previous routes
yeah
honestly, I don't know how to do this
but it'll keep me busy tonight xD
haha, would love to hear, Iโm trying to figure on my end as well, if I figure Iโll post here
Give this a try
The first rewrite does the data re-organization that you're looking for but suffers from nested vectors (this is often a result of using cata).
The second rewrite "flattens" the structure
cool, I guess the last rewrite can be replaced with flatten, got the same result here
not sure if its a fixable issue, but when I tried with a real longer structure, it did stack overflow ๐
It's funny - I'm so used to using meander that I reached for meander to flatten the data without even thinking of flatten ๐
cata does stack-based recursion so a sufficiently deep structure could result in an overflow, I guess
Let me see if I can rewrite it to avoid some of the recursion
I donโt think its that deep, from a quick look I guess its less than 10 depth
Can you post the structure?
stack overlow occurs when cata loops indefinitely
I assume you're getting the SO from the first rewrite?
sadly no, but there are a few other patterns that needs to be taken in account
and I guess those are screwing it up
Unfortunately, I'm not very familiar with these routing data structures
(m/rewrite 1
(m/app inc ?x)
(m/cata ?x))
I recommend using cata with instructions
I can make a shorter version that has more of those features, let me check
cool
is more readable and harder to error with an infinite loop
(m/rewrite [:start 1]
[:start (m/app inc ?x)]
(m/cata [:end ?x])
[:end ?x]
~(str "end with ?x = " ?x))
you can easily set checkpoints and also check which instruction will be executed next
found a simple stack overflow example:
'["v1"
["/foo"
["/baz" {:post baz-handler}]
["/other" []]]
["/bar"
{:get bar-handler
:post post-bar}]]sometimes instead of a map, its a vector with interceptors on the right side
ah, yeah. I can see how this would overflow
I'll take a crack at this data structure
feels a little ambiguous case, curious to see what you come with for that ๐
ha
you read my mind
unctions? fI'm guessing the vector of interceptors is always a vector of
functions?
What does the result for this look like?
the real one looks more like this:
'["v1"
["/foo"
["/baz" {:post baz-handler}]
["/other" [[:interceptor
[{:features {:policy-authz-enabled? false},
:interceptor [:scope
{:scope "xxx"}]}
{:features {:policy-authz-enabled? true},
:interceptor [:scope
[{:policy "yyy"}]]}]]]]]
["/bar"
{:get bar-handler
:post post-bar}]]but Iโm not sure all possible variations (like if they always start with double vector)
I've got a meeting in 5 minutes but I'll pick this up after
thanks, Iโll keep playing here too
seems like a notable difference is that those never start with strings at the beginning of the vector
only routes do that
(m/rewrite '["v1"
["/foo"
["/baz" {:post baz-handler}]]
["/bar" {:get bar-handler :post post-bar}]]
(m/with [%1 (m/map-of !methods !handlers)
%2 [(m/app #(str (last !paths) %) !paths) . (m/or %2 %1) ...]]
%2)
[{:url !paths :method !methods :handler !handlers} ...])
I can't make it any shorter @wilkerlucio
๐
looks nice!
on the large example it didnโt match though =/
but Iโll play with it
it probably because of the interceptors in the middle
what should be returned from the longer one?
\other should be omitted?
omitting other is good
the longer one currently returns nil, so something is going bad in the middle, Iโm trying to get a case to reproduce with your solution
(m/rewrite '["v1"
["/foo"
["/baz" {:post baz-handler}]
["/other" [[:interceptor
[{:features {:policy-authz-enabled? false} ,
:interceptor [:scope
{:scope "xxx"}]}
{:features {:policy-authz-enabled? true} ,
:interceptor [:scope
[{:policy "yyy"}]]}]]]]]
["/bar"
{:get bar-handler
:post post-bar}]]
(m/with [%1 (m/map-of !methods !handlers)
%2 [(m/pred string?) _]
%3 [(m/app #(str (last !paths) %) !paths) . (m/or %3 %2 %1) ...]]
%3)
[{:url !paths :method !methods :handler !handlers} ...])
\other catches under %2, which is defined in the simplest possible way, [string? whatever]
here is an example thatโs going off, but not the main problem yet:
(m/rewrite '["v1"
["/foo"
[:some-interceptors]
["/baz" {:post baz-handler}]
["/other" [[:interceptor
[{:features {:policy-authz-enabled? false},
:interceptor [:scope
{:scope "xxx"}]}
{:features {:policy-authz-enabled? true},
:interceptor [:scope
[{:policy "yyy"}]]}]]]]]
["/bar" {:get bar-handler :post post-bar}]]
(m/with [%1 (m/map-of !methods !handlers)
%2 [(m/pred string?) _]
%3 [(m/app #(str (last !paths) %) !paths) . (m/or %3 %2 %1) ...]]
%3)
[{:url !paths :method !methods :handler !handlers} ...])probably with a more complicated example it will fall in a different place
(in this case the :some-interceptors should be ignored)
anyway you guys are meander masters, its already really helpful ๐
not so much
I see that it is probably wrong, because it does not return a map with the path :url foo/bar ๐
but I'm glad I could help a little.
It would be nice if @noprompt offered a solution
I have no idea how to better concatenate urls into one, and what I've done doesn't always work
the examples you posted are nice as well, Iโll spend some time to understand and learn those patterns ๐
Thanks for showing with @huxley ! I was aware of it but I don't think I've ever used it before
โบ๏ธ
this worked!
(m/rewrite
(-> data :ig/system :pipo.module/web-routes :routes ffirst)
(m/with [%route-map (m/map-of !methods !handlers)
%item [(m/pred string?) _]
%interceptors [(m/pred keyword?) . _ ...]
%all [(m/app #(str (last !paths) %) !paths) . (m/or %all %item %interceptors %route-map) ...]]
%all)
[{:url !paths :method !methods :handler !handlers} ...])thank you again folks!
I celebrated too soon, @huxley I found this way to concatenate is not doing the stack as expected, on the base example it outputs:
[{:url "v1", :method :post, :handler baz-handler}
{:url "v1/foo", :method :get, :handler bar-handler}
{:url "v1/foo/baz", :method :post, :handler post-bar}]but it should be
({:url "v1/foo/baz", :method :post, :handler baz-handler}
{:url "v1/bar", :method :get, :handler bar-handler}
{:url "v1/bar", :method :post, :handler post-bar})
(which is the result given frmo the @markaddleman solution)now trying to work more on the mark example to add the interceptors part
I thought you guys already had a solution so I didn't pick up the interceptor piece. I'll give it a look tomorrow morning
thanks, this is the example Iโm working on top of now:
'["v1"
["/foo"
[:some-interceptors]
["/baz" {:post baz-handler}]]
["/bar" {:get bar-handler :post post-bar}]]you can forget the value as vectors, that wasnโt a thing, just the interceptors in the middle ๐
got it ๐ ๐
(-> '["v1"
["/foo"
[:bla :me []]
["/baz" {:post baz-handler}]]
["/bar" {:get bar-handler :post post-bar}]]
(m/rewrite
[?path (m/map-of !action !handler)]
[{:url ?path :method !action :handler !handler} ...]
[?path-prefix [(m/pred keyword?) & _] & ?rest]
(m/cata [?path-prefix & ?rest])
[?path-prefix [?path-suffix & ?deeper-or-handlers]]
(m/cata [(m/app str ?path-prefix ?path-suffix) & ?deeper-or-handlers])
[?path-prefix . !deeper ...]
[(m/cata [?path-prefix !deeper]) ...])
flatten)
that was fun to learn! thanks folksSorry I missed this conversation. I was out with a few doctor appointments for myself and my son. ๐