You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm open to any feedback regarding this proposal. Would be useful to get some discussion from other rust devs about the server development experience they want.
Proposal for Potential Rust Server Implementation
Of the high performance backend languages the Rust ecosystem provides tooling that makes creating a code-first implementation of an Arri server really straightforward (at least in concept it's straightforward). My proposed rust implementation suggests the usage of Procedural Macros to automatically create the App Definition and automatically handle parsing and serialization.
Procedures can be marked with another proc macro, which will act as syntaxtic sugar for creating an HTTP endpoint the "Arri" way. We can use the Leptos Server Functions as a potential reference for this. We can also enforce that the first parameter must be a struct that has derived ArriModel or whatever we end up calling it, and also enforce that Rpc functions must return a result type of Result<T, ArriError> where T is an ArriModel
I haven't quite figured out the API for this part yet, but we need to register the procedures on the application itself. I know that somehow Leptos is able to do this automatically (i.e. you don't need to import your server functions and register them on the app instance). So it's worth looking into that. Ideally this would be done in such as way that:
The inputs and outputs of procedures automatically get registered in the App
Procedures can be grouped into services similar to the typescript implementation (ex: users.getUser)
We can implement this in such a way that we don't force Rust users to use a specific HTTP framework. (I.e. users can use Axum or Actix or whatever)
Creating a Rust Server Plugin For Arri
That last thing would be to create an arri rust server plugin that knows how to run the rust server and knows where the rust app will output the App Definition file.
// The following is all psuedo-codeconstrustServer=defineServerConfig({devFn(_,generators){// run the serverletrustProcess=spawn("cargo run",{stdio: "inherit",});// start watching wherever we expect the rust app to output the App Definition for changesconstappDefWatcher=startFileWatcher(".arri/app_definition.json");appDefWatcher.on("change",async()=>{// reread the app definitionconstappDef=JSON.parse(fs.readFileSync(".arri/app_definition.json","utf8"))asAppDefinition;// pass it to the generatorsawaitPromise.all(generators.map((item)=>item.generator(appDef)));});// starting watching our rust source codeconstsrcCodeWatcher=startFileWatcher("./src/**/*.rs");srcCodeWatcher.on("all",async()=>{// if a change is made to the source code kill the rust process and restart itrustProcess.kill();rustProcess=spawn("cargo run",{stdio: "inherit",});});},buildFn(_,generators){// build the serverexecSync("cargo build",{stdio: "inherit",});// run the app with some kind of flag indicating we don't want the server to start// but rather than we just want the app definition// this flag is something we can make every rust arri app check for maybe?execSync("./path/to/executable --codegen-only");// parse the app definition and pass it to the generatorsconstappDef=JSON.parse(fs.readFileSync(".arri/app_definition.json","utf8"))asAppDefinition;awaitPromise.all(generators.map((item)=>item.generator(appDef)));},});
Anyway feedback welcome. Conceptually it's straightforward, realistically it's a lot to implement - particularly creating the proc macros for generating type definitions.
Additional Notes
We probably need to avoid using Serde because it doesn't support DateTime, but also we already need to create our own derive macros so we might as well handle parsing and serialization too. This will also give us more control over how things get parsed and serialized.
Some thought also needs to be given to how we will allow for passing of the request "context". Basically we should be able to access the user session, headers, and other stuff that might be relevant.
The text was updated successfully, but these errors were encountered:
I'm open to any feedback regarding this proposal. Would be useful to get some discussion from other rust devs about the server development experience they want.
Proposal for Potential Rust Server Implementation
Of the high performance backend languages the Rust ecosystem provides tooling that makes creating a code-first implementation of an Arri server really straightforward (at least in concept it's straightforward). My proposed rust implementation suggests the usage of Procedural Macros to automatically create the App Definition and automatically handle parsing and serialization.
Table of Contents
Defining Types
Types can be marked with a custom derive macro which will add functions for
The macro could look something like this
Which would implement a
to_type_def()
method that outputs the following ATD:We could also provide an additional annotation to denote the casing of the JSON keys:
The mapping of Rust primitive types to ATD primitive types would be as follows:
Handling Optional Fields
Option types will automatically be marked as an optional property when outputting to JTD. So this,
Will become,
An additional annotation could be added for instances where you would prefer to serialize the type as
null
instead of omitting it from the responseEnums and Discriminated Unions
For discriminated unions we will need to add some restrictions. Either none of the enums have properties or all of the enums have properties.
Basic Enum
A basic enum would look like this
Which would become the following in ATD
Tagged Unions
A tagged union would require all enum variants to have at least 1 property
Would output the following ATD:
Defining Procedures
Procedures can be marked with another proc macro, which will act as syntaxtic sugar for creating an HTTP endpoint the "Arri" way. We can use the Leptos Server Functions as a potential reference for this. We can also enforce that the first parameter must be a struct that has derived
ArriModel
or whatever we end up calling it, and also enforce that Rpc functions must return a result type ofResult<T, ArriError>
whereT
is anArriModel
So for example
Becomes
And get's represented as the following in the App Definition
Additional annotation inputs could be use to manually override things like the endpoint path, http method, etc.
Registering Types and Procedures
I haven't quite figured out the API for this part yet, but we need to register the procedures on the application itself. I know that somehow Leptos is able to do this automatically (i.e. you don't need to import your server functions and register them on the app instance). So it's worth looking into that. Ideally this would be done in such as way that:
users.getUser
)Creating a Rust Server Plugin For Arri
That last thing would be to create an arri rust server plugin that knows how to run the rust server and knows where the rust app will output the App Definition file.
Anyway feedback welcome. Conceptually it's straightforward, realistically it's a lot to implement - particularly creating the proc macros for generating type definitions.
Additional Notes
We probably need to avoid using Serde because it doesn't support
DateTime
, but also we already need to create our own derive macros so we might as well handle parsing and serialization too. This will also give us more control over how things get parsed and serialized.Some thought also needs to be given to how we will allow for passing of the request "context". Basically we should be able to access the user session, headers, and other stuff that might be relevant.
The text was updated successfully, but these errors were encountered: