I am writing a server, that offers dozens of API funtions. The number is likely to get bigger in the future. At the moment I am porting the request handling to Rust and I am struggling what the most idiomatic, safe, flexible or future-proof solution is.
My server is basically doing this for each request:
- Decode request
- Check authorization
- Execute request
- Encode answer
- Create log string
One easy and powerful solution I can see is just building huge enums, that contain all necessary information for one step. I like that a lot, except the huge match
blocks that will be necessary. Let's assume this architecture:
enum Request {
DoSomething { param1: u32 },
DeleteEntry { id: [u8; 16] },
}
enum Answer {
BufferAnswer { buffer: Vec<u8> },
ValueAnswer { value: u32 },
}
enum UserRole {
Admin,
Elevated { val1: u32 },
User { val1: u32, val2: u32 },
}
I could now have functions like:
fn decode_request() -> Request
fn encode_answer(answer: &Answer)
that encapsulate the wire protocol (which is not relevant for the server logic).
Checking the authorization and executing the request would just give a enormous match
. I probably would need to access some of the role values during this. So I probably would end up with something like this:
match (request, role) {
(
Request::DoSomething { param1 },
UserRole::Elevated { val1 } | UserRole::User { val1, val2: _ },
) => {
execute_do_something(param1, val1);
}
}
Is this good idiomatic Rust? Is it efficient? Are there other ways to do it?