Procedure
A procedure represents a single operation which can be executed on your server. You define procedures which are collected up into a router.
Procedure setup
The following code can be copied as the base setup for defining procedures. Although this may look like a lot of boilerplate, any non-trivial application will end up with all of these components.
Defining a procedure
The following code shows how to define a procedure and attach it to a router. rspc allows many procedures to be attached to a single router which allows logical grouping of procedures such as by feature or domain model.
Using custom types
For rspc to be able to convert your types into Typescript they must implement the specta::Type
trait. Specta is a crate that was created so that rspc can introspect Rust types. The Type
trait allows the Typescript exporter to understand the fields, generics and dependant types of a Rust type.
The easiest way to implement the specta::Type
trait is by using the specta::Type
derive macro. We have already implemented most in-built types if you can find a missing one open a GitHub Issue.
Request Context
When calling execute on a operation you must provide a request context. The type of the request context must match the TCtx
generic parameter defined on the rspc::Router
.
Using request context is important because it means you can construct the router without a dependency on anything (such a database) which allows you to validate the router in a unit test. The routes are stringly typed so we can't just rely on Rust's compiler to validate the router. This tradeoff was made for the superior developer experience as we believe using request context and a unit test for validating the router is able to mitigate the risk.
A request context is created on every request and can hold any data the user wants. The request context also abstracts the underlying transport layer such as HTTP, Websocket or Tauri so that the router can be agonistic to which one is being used.
Capturing variables
rspc allows for capturing variables in the closure of a procedure. This is generally fround upon as it put a requirement on that value when creating the router which could limit your ability to unit test the router. More of the logic behind this is explained in request context section below. This is a general rule and you will likely find exceptions.
Error handling
rspc procedures have to return the type Result<T, rspc::Error>
where T
can be any type which can be returned from a normal procedure.
The fact that Rust as a language currently requires the error type to be concrete makes error handling slightly annoying. All of the error handling done by rspc relys on the question mark operator (?
) in Rust to make a reasonable developer experience. The question mark operator will expand into something along the lines of return Err(From::from(err))
under the hood. This means for any type T
if you implement From<T> for rspc::Error
you will be able to rely on the question mark operator to convert it into an rspc::Error
type.
TODO
- Put recommended file names on the code snippets???
- Go through and breakdown the generics/parts. What traits the input/return types need, etc.
- Example using
anyhow
- Example exposing strings to the frontend
- Show examples extending
BaseProcedure
- Why not middleware on router?
- Error handling
Last updated on