Releases: specta-rs/rspc
v0.4.0 - A long time in the making
Today marks the well anticipated release of rspc 0.4.0. This release has been over 2 years in the making and opens up a whole new world of possibilies.
Note: Currently none of the documentation has been upgraded to show the new syntax (#339). If you've got some time to spare a PR would be appreciated!
Changes
New Procedure Syntax
The new syntax looks like the following:
pub fn mount() -> Router<Ctx> {
Router::new()
.procedure("login", {
<BaseProcedure>::builder()
.query(|ctx, input: LoginRequest| ...)
})
.procedure("me", {
<BaseProcedure>::builder()
.with(auth())
.query(|ctx, _: ()| ...)
})
}
We have moved middleware from being applied to the router to being applied to the procedures themselves. This makes for much better composition and opens up many new usecases for middleware.
With this new syntax you are also responsible for defining BaseProcedure
and Error
. This may seem like a lot of boilerplate but it makes rspc way more flexible, which makes it scale much better as your codebase gets bigger. It can be defined as:
`BaseProcedure` + `Error` definition
use thiserror::Error;
use serde::Serialize;
use specta::Type;
#[derive(Debug, Error, Serialize, Type)]
#[serde(tag = "type")]
pub enum Error {}
impl rspc::Error for Error {
fn into_procedure_error(self) -> rspc::ProcedureError {
rspc::ResolverError::new(self, None::<std::io::Error>).into()
}
}
pub struct BaseProcedure<TErr = Error>(PhantomData<TErr>);
impl<TErr> BaseProcedure<TErr> {
pub fn builder<TInput, TResult>(
) -> rspc::ProcedureBuilder<TErr, Ctx, Ctx, TInput, TInput, TResult, TResult>
where
TErr: rspc::Error,
TInput: rspc::ResolverInput,
TResult: rspc::ResolverOutput<TErr>,
{
rspc::Procedure::builder() // You add default middleware here
}
}
This change in syntax is very similar to what tRPC did for tRPC v9 to tRPC v10. A huge thanks to @alexdotjs for his influential work on tRPC!
New middleware syntax
The syntax needs some major documentation but we have also overhauled middleware to make them more flexible and give them access to switch the input and result type, along with accessing the input and result types in a typesafe manor.
We are also going to be releasing a suite of official middleware in the near future. A lot of them are in active development within the rspc repository.
If your interesting the new syntax is:
pub fn my_middleware<TError, TCtx, TInput, TResult>() -> Middleware<TError, TCtx, TInput, TResult>
where
TError: Send + 'static,
TCtx: Send + 'static,
TInput: Send + 'static,
TResult: Send + Sync + 'static,
{
Middleware::new(
move |ctx: TCtx, input: TInput, next| async move { next.exec(ctx, input).await },
)
}
Glimpse into the future
Typesafe errors
This release supports typesafe error values on the backend. Your error types can be serialized and there types will be exported via Specta to your frontend.
We are currently lacking Typescript client support for this but it will be coming in a following up release.
Upgrading
Using rspc_legacy
You can change your imports from rspc
to rspc_legacy
to keep your legacy routers working on the new core. This will allow you to incrementally migrate procedures.
We have also renamed rspc-tauri
to tauri-plugin-rspc
so ensure you update your imports.
Checkout the legeacy example which shows how to do this.
Fully migration
Once your using rspc_legacy
you can start migrating each router at a time to the new syntax.
Refer to the examples to see how the new syntax works.
v0.3.1 - General fixes
v0.3.0 - Tauri v2 Support!
Changes:
- Upgrade dependencies - Including support for Tauri v2!
- This version requires Specta
=2.0.0-rc.20
- Remove a lot of
rspc::internal
exports to prepare for major changes to the internals.
v0.2.0
This release comes with a bunch of breaking changes to prepare existing rspc projects for the upcoming 0.3.0 release.
This release is only possible due to the support of my sponsors!
A huge thanks to @scottwey, @michael-dm and @TmLev for supporting me. If you are using rspc and you or your company is able to support the project it would be greatly appreciated as it ensures the product is sustainable long-term!
tldr of changes
- Fix websocket when using the Axum integration which I broke in the
0.1.4
release earlier today - Drop
httpz
from rspc core. I have deprecated this crate as I don't think it's serving it's purpose very well. All integrations are moving intorspc_*
crates. - Remove Specta reexports and Specta features from the rspc crate
- Restart subscriptions and in-progress requests when the websocket connection reconnects.
- Websocket support is now optional and requires the
ws
feature to be enabled on therspc_axum
crate. - Expose
AppHandle
to Tauri context function as the first argument - fixes #244
These changes should hopefully fix the most comments issues I hear when talking with people about rspc.
Upgrade Guide:
Bump dependency versions
# Backend
cargo add [email protected]
# Frontend
pnpm install @rspc/[email protected]
pnpm install @rspc/[email protected]
pnpm install @rspc/[email protected]
pnpm install @rspc/[email protected]
Removal of rspc::Type
rspc::Type
is currently a reexport of specta::Type
and to make versioning easier we have removed it in this rspc release. To upgrade:
Make sure you have Specta installed in your project.
cargo add specta
Then replace all rspc::Type
imports with specta::Type
.
Removal of many features from rspc
crate
This release drops a lot of features from the rspc
crate. I have documented them by category below:
Specta-related flags
This includes uuid
, chrono
, time
, bigdecimal
, rust_decimal
, indexmap
, ipnetwork
, mac_address
, bit-vec
and bson
.
You should instead move the feature onto the specta
crate.
Eg.
- rspc = { version = "0.1.4", features = ["chrono"] }
+ rspc = "0.2.0"
+ specta = { version = "1", features = ["chrono"] }
Webservers
This includes httpz
, tauri
, axum
, lambda
, workers
. You should follow the guide for your integration under the next heading.
Break out integrations into dedicated crates
This is going to make versioning significantly easier which would mean more frequent bug fixes and depedency upgrades.
This included removing .endpoint
and the rspc::integrations
module in favor of splitting the logic over multiple crates.
Follow the guide below based on your chosen integration:
Axum
First, remove the old feature flag and add the new rspc_axum
crate.
- rspc = { version = "0.1.4", features = ["axum"] }
+ rspc = "0.2.0"
+ rspc_axum = { version = "0.1.1", features = ["ws"] } # Websocket support is now optional
Next, upgrade the code in your project:
let app = axum::Router::new()
.route("/", get(|| async { "Hello 'rspc'!" }))
.nest(
"/rspc",
- router
- .clone()
- .endpoint(|| { ... })
- .axum(),
+ rspc_axum::endpoint(router.clone(), | | { ... }),
)
.layer(cors);
Tauri
First, remove the old feature flag and add the new rspc_tauri
crate.
- rspc = { version = "0.1.4", features = ["tauri"] }
+ rspc = "0.2.0"
+ rspc_tauri = { version = "0.0.1" }
Next, upgrade the code in your project:
tauri::Builder::default()
- .plugin(rspc::integrations::tauri::plugin(router.arced(), || { ... }))
+ .plugin(rspc_tauri:plugin(router.arced(), |_| { ... }))
Lambda
This feature has been removed. It's recommend you use the Axum integration with cargo-lambda
like this example.
Workers
This feature has been removed. It currently has no direct replacement but will be brought back in the near future.
If you are actively using it, please contact me on the rspc/PCR Discord and we can get something sorted.
Tanstack Query v5
This release requires you upgrade to Tanstack Query v5. You can follow their upgrade guide here.
Solid Query
Solid Query has changed the way its arguments are parsed upstream so we decided to copy this. You will need to update all of your createQuery
, createMutation
, etc hooks to the new syntax.
For queries you will need to make the following changes:
rspc.createQuery(
- () => ["echo", "somevalue"],
- () => ({
- enabled: true,
- })
+ () => ({
+ queryKey: ["echo", "somevalue"],
+ enabled: true
+ })
);
For mutations, you will need to use the mutationKey
property to choice the mutation is the same style.
Usage with Prisma Client Rust
If your using Prisma Client Rust 0.6.x
you can use the rspc-0.2.0
branch:
prisma-client-rust = { git = "https://github.com/Brendonovich/prisma-client-rust", rev = "8faf98013d0d2c7fab68fad387305a55979e777d" }
prisma-client-rust-cli = { git = "https://github.com/Brendonovich/prisma-client-rust", rev = "8faf98013d0d2c7fab68fad387305a55979e777d" }
v0.1.4
Changes:
- Support Axum 0.7
- Fix rspc Tauri can only handle one request at a time - #260 - Thanks @campbellcole
Using Axum 0.7
To use Axum 0.7 you must use the rspc_axum
crate. You will need to install it by running:
cargo add [email protected]
and then make the following changes:
let app = axum::Router::new()
.route("/", get(|| async { "Hello 'rspc'!" }))
.nest(
"/rspc",
- router
- .clone()
- .endpoint(|| { ... })
- .axum(),
+ rspc_axum::endpoint(router.clone().endpoint(|| { ... })),
)
.layer(cors);
Warning
I noticed after publishing this release, it's got a major bug with Websockets due to mistake on my end. If you are using websockets please jump straight to 0.2.0 instead, sorry for the inconvenience!
I also forgot to publish to npm for this release.
😊
v1.0.0-rc.4
Foreshadowing: I really hope no more bugs exist.
v1.0.0-rc.3
The bugs just don't stop coming.
v1.0.0-rc.2
Bug fixes
v1.0.0-rc.1
v0.1.3
Fixes:
Changes
- Specta has been relocated from the specta subdirectory to oscartbeaumont/specta
- Specta has been upgraded to v1.0.0
- Support for Axum v0.6
- Multithreaded Tauri executor
- Upgraded all Rust and backend deps
- Remove
async-stream
dependency
Breaking changes
Axum integration
When upgrading you will get the error expected struct "MethodRouter", found struct "axum::Router"
. To fix this you need to update your code as follows:
+ use rspc::integrations::httpz::Request;
- .route(
"/rspc/:id",
+ .nest(
"/rspc",
router
- .endpoint(|path: Path<String>| {
- println!("Client requested operation '{}'", *path);
+ .endpoint(|req: Request| {
+ println!("Client requested operation '{}'", req.uri().path());
()
})
.axum(),
)
If you were using a full Axum extractor, support for them has been deprecated as Axum 0.6 has broken the way it works. Please refer to this example for the workaround to use an Axum extractor. This workaround will be removed in the future so please open a GitHub issue to let me know your usecases for it!
Merge behavior
The behavior .merge
has changed. If you want to restore the old behavior rename .merge
to .legacy_merge
. I am going to drop .legacy_merge
in a future update so please open a GitHub Issue if you have a use case that doesn't work with .merge
.
Other Dependencies
You may be required to upgrade over dependencies such as:
- Tokio
- Axum
I would highly recommend installing cargo-edit and running cargo upgrade --compatible --recursive
to upgrade everything.