Remix Jokes with a decoupled Node.js API
This project came to be because of an excellent tutorial made by the Remix Team called Jokes. I highly recommend it.
I wanted to see if I could have an API running on a server and other front ends running on separate servers. This is the "boring and proven" way it has been done for years.
Why would I want a separate API?
Even though Remix is a full-stack web framework and you can have an awesome experience deploying just one application that handles everything (including Resource Routes), I prefer to have the API decoupled from the frontend. This way I can have other frontend projects decoupled from Remix like a React Native app or maybe a Next.js admin app.
Having a decoupled API also lets me deploy it on a different server or serverless functions.
Another benefit of having the API/APIs decoupled is that there is no "vendor lock-in" to a particular front end stack. I'm excited about Remix and I see an amazing future for it, but I like to try new things and I love experimenting with the front end, so I want to have a reliable boring API and experiment with the front ends.
What's this project about?
In the following example, we have a Remix app from the Jokes Tutorial that connects to the User and Jokes API made with Express + PostgreSQL.
Auth
I also included JWT auth with Refresh Tokens in Redis. Auth tokens are saved to the cookie session and refreshed through "authenticated loader API calls" in Remix. You can find how this is done in the public GitHub repo.
The API also contains authorized routes for the user and joke models.
Deployment
The backend also contains config to deploy in AWS Elastic Beanstalk.
The Postgres DB is deployed to AWS RDS.
Even though I opted for this deployment, since it's one of the most common and proven technology stacks, you can probably deploy it anywhere you want.
Backend
Node.js Backend deployed with AWS Elastic Beanstalk and RDS:
- Typescript
- Auth Server (JWT with Access and Refresh tokens)
- Redis Server (for refresh tokens blacklist)
- Authenticated routes.
- Prisma
- PostgreSQL
- AWS Elastic Beanstalk + AWS RDS deployment (boring and proven)
Frontends
We have a Remix app that connects to the backend. We can deploy it to different places since it's just a Remix project.
From this project we could also add more frontend apps that share to the same backend like a React Native app, giving us not only a lot of freedom to add, remove or change frontends but deploy each part in different technologies, like having the frontend in mobile app stores.
We could also have the Remix app deployed at the Edge using serverless and the backend in multi regions with replicas for the PostgreSQL DB and then completely change it to a different infrastructure in the future as the project scales and changes requirements.
Monorepo and Multirepo
I made two projects. One is a monorepo and the other is a multirepo.
Monorepo project
-
The monorepo project shares Prisma generated Typescript types because it shares the Prisma Client dependency in the root node_modules folder.
-
TODO: GitHub Actions for remix-jokes-backend have not been tested since it's now a monorepo.
Multirepo project
- TODO: Because this is not a monorepo, we cannot generate the types for Prisma in the common root node_modules folder that includes @prisma/client. The current solution is to use the remix-jokes-frontend/app/prisma.d.ts file that contains a copy of the generated types but we hace to do this manually. There are multiple solutions for this that include things such as: npm package, git submodule, symlinks, and many more.