github clockworklabs/SpacetimeDB v1.10.0
Release v1.10.0 - Procedures and HTTP Requests

8 hours ago

Today we have an absolute game changer for SpacetimeDB. SpacetimeDB 1.10 introduces the ability for databases to perform HTTP requests to external services right from within your module! This is one of our most-requested features, and we're very excited to share it with you all.

SpacetimeDB Reducers are extremely powerful. They are atomic, transactional, pure, retryable, and replayable. The challenge was: in order to maintain these properties and guarantees, they need to be isolated from the outside world and can't be allowed to cause any observable side effects.

However, HTTP requests are inherently side-effecting, and are too useful not to have. It turns out the solution is pretty simple: keep reducers side effect free, and introduce a new kind of database function with weaker guarantees and more powers. Enter a new type of SpacetimeDB function: Procedures.

Examples

Just like a reducer, a procedure is a function defined in your module which runs inside the database. Unlike a reducer, procedures don't correspond 1-to-1 with transactions. Instead, you explicitly manage transactions inside the body of your procedure:

#[spacetimedb::procedure]
fn find_highest_level_player(ctx: &mut ProcedureContext) {
    let highest_level_player = ctx.with_tx(|ctx| {
        ctx.db.player().iter().max_by_key(|player| player.level)
    });
    match highest_level_player {
        Some(player) => log::info!("Congratulations to {}", player.id),
        None => log::warn!("No players..."),
    }
}

Being able to run code in the database without a transaction open opens a lot of possibilities for new APIs we could expose. The first of these, releasing today, is HTTP requests:

#[spacetimedb::procedure]
fn get_request(ctx: &mut ProcedureContext) {
    match ctx.http.get("https://example.invalid") {
        Ok(response) => {
            let (response, body) = response.into_parts();
            log::info!(
                "Got response with status {} and body {}",
                response.status,
                body.into_string_lossy(),
            )
        },
        Err(error) => log::error!("Request failed: {error:?}"),
    }
}

Take a look at the documentation on the new procedure APIs for more details,
and join us on Discord to let us know what other side effects you want APIs for!

As of this release, only Rust and TypeScript modules can define procedures. We're hard at work adding support to C# modules, and will be releasing them soon. We'll also be cleaning up the new APIs in response to your feedback, so for now procedures are unstable and subject to breaking changes.

TypeScript fixes

In this release, we've also fixed quite a few issues which were reported in the new TypeScript SDK.

  • This issue by exporting the SubscriptionHandle type with the REMOTE_MODULE type applied.
  • This issue by converting to camelCase for column names in code generation.
  • Fixes an issue where onMyReducer callbacks were passing arguments as variadic params, while the types indicated they would be passed as an object. onMyReducer((ctx, argA, argB, argC) => {}) vs onMyReducer((ctx, { argA, argB, argC}) => {})`
  • Fixes an issue where the table type name was used instead of the table name in code generation for constructing tables.
  • Fixes issue with ScheduleAt being used in non-table types.
  • Fixes issue where template projects do not use the correct lifecycle reducer setup
  • Fixes an issue where .insert() returns incorrect objects
  • Fixes an issue where .update() causes error with .autoInc() field

We intend for TypeScript modules and clients to rapidly approach stability. The most invasive breaking changes have already been made.

What's Changed

New Contributors

Full Changelog: v1.9.0...v1.10.0

Don't miss a new SpacetimeDB release

NewReleases is sending notifications on new releases.