Fork me on GitHub
#reitit
<
2023-01-05
>
Tema Nomad13:01:10

I am still dont understand how to structure Reitit routes for a full-stack application, where we have API backend part and CLJS frontend part. I have shared cljc routes and use it with custom expand func both in frontend and backend code I tried to build this structure: • Frontend app on the root / path with routes like these: /login, /todos etc • Backend app on the /api path with routes like these: /api/todos, /api/auth etc But I could not find the way to do it Then I tried to build following structure: • Frontend app on the root /app path with routes like these: /app/login, /app/todos etc • Backend app on the /api path with routes like these: /api/todos, /api/auth etc And I think it works well, but what is about middleware? I need to apply them only for backend routes, how to do it?

robert-stuttaford13:01:04

we don't use the expander thing, and instead just use cljc injections

[["/top" ?#@(:clj [:interceptors [some-interceptor]])
  ["/page" {:name :page
            ?#@(:clj [:get {:handler my-handler-fn}])}]]]

robert-stuttaford13:01:33

this way we have fine-grained control at the Read step rather than as a runtime Eval step

robert-stuttaford13:01:03

client side we use the by-name method to generate paths for api requests / links to other pages in the app, server side we use the reitit http router

Tema Nomad14:01:04

But how ring server will know all backend/frontend routes (to understand when to show 404), if you cut the frontend part inside your ‘cljc’ file?

robert-stuttaford14:01:19

it may be helpful to understand that you're not building one app, you're building two

robert-stuttaford14:01:34

you can use cljc conditionals to control which app gets to see which parts of the route table

robert-stuttaford14:01:45

you might conditionally keep some routes clj only, and some cljs only

robert-stuttaford14:01:11

if you have a catchall page e.g. /app* on the server, in which your cljs app will run and handle lots of /app/ routes like /app/foo and /app/bar, then you actually need two mutually exclusive routing tables - one that the server mounts (with the catchall), and one that the client mounts (with all the named routes). BUT, both the server and the client would need access to the latter for the purposes of generating links

robert-stuttaford14:01:26

a big reason for using reitit, is that it's all just data

robert-stuttaford14:01:42

so approach it as a 'data visibility in my app' problem first, and a routing problem second

robert-stuttaford14:01:16

another approach may be not to use catchall route, but instead to allow the server to directly render each route via server-side-rendering

robert-stuttaford14:01:23

in that case, client and server would share a routing table

Tema Nomad15:01:39

Thank you @U0509NKGK will try tomorrow

Tema Nomad07:01:53

is it correct? This way I create 1 cljc file where put all my front/back routes All routes has :name key so to use API routes on frontend

robert-stuttaford07:01:42

that's what we're doing, yes 🙂

robert-stuttaford07:01:12

we also conditionally add interceptors where appropriate, and sometimes provide some routes on the backend only

Tema Nomad07:01:09

Oh finally I start to understand that big reitit knowledge gap! Thanks man @U0509NKGK

Tema Nomad07:01:11

I need to add #?@(:clj [:get handlers/frontend-handler]) for each frontend route, is it ok or there is some way to avoid that code duplication? This route for the case when user load page in browser on some frontend route, not from root

Tema Nomad07:01:05

handlers/frontend-handler just renders html page with front-app mounted

robert-stuttaford09:01:36

i find that it's actually not all that much noise

robert-stuttaford09:01:55

it makes the fact and the intention clear; hiding it away makes the system feel less deterministic and more magical to me

robert-stuttaford09:01:32

to be clear, magic=bad in this context 😅