I am on a journey to achieve full type safety frontend to backend πΆπ»ββ‘οΈ
After bumping into some issues with server actions I discovered (effect) rpc.
And it was π€―
Stop using server actions, there is a better way, it's called @EffectTS_ rpc π β Type safe error handling β As simple as a function call β Full control on request and response When you start using it it works like magic πͺ
Here is the full story and all the pieces of my type-safe puzzle π§©
Frontend is becoming more backend-ish
Frontend used to be about styles, components, css and these kind of stuff ππΌββοΈ
Checklist before releasing that new frontend feature of your app β Accessibility β Responsiveness β Analytics events β Security β Error reporting β Bundle size β Performance Well, frontend is complex indeed π€
But then everyone realized that data must come from somewhere, and it's the frontend that is responsible to request it.
Result:
Promise
,Suspense
, error handling, loading state, and more and more.
We are about to reach a new dimension with React 19: Server components and Server actions ("server" you see π ).
Frontend is not only "front" anymore, it's time to upgrade your skills to "back" as well.
The convenience and cost of server actions
Server actions come to the rescue: execute server code as simple as a function call πͺ
Catchy promise, convenient, but with some limitations, some of which break my type-safe model:
- No error handling whatsoever
- Serialize/Deserialize is a pain
Error handling in server actions has a large room for improvements π€ When an action fails it always returns 500 error, which doesnβt help much with providing a clear error message on the client π Am I missing something?
How server actions work under the hood
Back to the drawing board then π§βπ«
How can I have the convenience of server actions (single function call) with full type safety?
Behind "a single function call" there are some layers that execute some magic:
- Serialize the function parameters
- Perform an http request to the server passing the parameters in the body
- Deserialize (validate/parse) the parameters on the server
- Perform the request on the server
- Serialize and return the response to the client
- Deserialize the response on the client and provide it as the return of the function called initially
From client to server, all in a single function call
All of these also need to include error handling and serialization/deserialization "out of the box".
Solution: Effect + Effect Schema
There is more π€©
Timeless coding principles, practices, and tools that make a difference, regardless of your language or framework, delivered in your inbox every week.
Effect rcp: type safe from client to server
Turns out the solution was hiding in plain sight: @effect/rpc
πͺ
It works as described above, with the full power of effect
for error handling and @effect/schema
for serialize/deserialize requests, all provided out of the box:
- Define
TaggedRequest
using@effect/schema
(error, success, parameters) - Define shared
Router
implementation (server requests) - Execute the request on the server (single api endpoint)
- Define http request parameters on the client
- Execute request just like a normal
Effect
This is all type safe end-to-end: the types are shared between client and server π₯
Use @EffectTS_ rpc on the client, as simple as a function call πͺ π Export HttpResolver that performs a request to the rpc endpoint π Make a request with a single function call π Both request and return type is fully typed (success and error)
Type safety everywhere
My journey to type safety continues:
- The server is as type safe as possible with
effect
- Improvements on client/server communication using
@effect/rpc
- Powerful and type safe state management on the client using
xstate
You may have heard the saying: "If it compiles it works" π
This is the final destination. When you reach that ideal one of 2 things can happen:
- The app works and there are no runtime issues π
- The app doesn't compile, which means the problem is "technically" no solvable. This is usually a sign of some missing detail in the requirements or the domain design, that you can solve before releasing in production π
Speaking of type safety, I am working on something new that may probably interest you (since you are reading this) π
This is coming in something I am working on that I'll announce soon π
I am about to announce it soon. Rest assured that you will get to know about it before everyone else as part of this newsletter π
See you next π