I have some client/server crate, where client uses shared structs model to parse JSON response from the server (by serde crate).
For example, some server struct members should be reachable in client:
use serde::Deserialize;
#[derive(Deserialize, Debug)]
struct Response {
online: bool,
} // struct defined on server and duplicated in client (hardcoded)
use openlegends_client::Client;
#[test]
#[ignore]
fn _new() {
let host = "127.0.0.1";
let port = 4321;
let mut client = Client::new(host, port).unwrap();
assert!(
serde_json::from_str::<Response>(&client.status().unwrap())
.unwrap()
.online
);
}
Same for request structs not implemented yet. I won't duplicate them (using hard code in client), or make new crate for shared headers. Thoughts organize these structs as the part of server library and mark with feature attributes (e.g. headers) - that also useful because client API will be always related / synced with specified server version, defined in own Cargo.toml
But yet not sure how to prevent entire server build in the client library after add with cargo to dependencies. Or the client will not use anything but members defined as the server lib?
Maybe the main question here is do I really want new crate, because I can define everything shared in server lib.rs and require it (server lib) in the client (using same server version also)
not sure only, must I use feature attributes to skip entire server build for the client, or everything not the main.rs will be skipped when added by cargo add crate as the client dependency
p.s. new crate require additional versions maintenance when lib.rs does not.
Finally, defined these 'shared' structs as the part of server library,
by this way, server members from main.rs not accessible for client just entire server crate should be compiled (that means all dependencies should be installed also, like sqlite3)
Maybe later I'll create separated crate for headers, but currently won't manage versioning.
A small shared crate is better because your client does not need to depend upon or build your entire server. Likewise your server does not need to depend upon or build your entire client.
FWIW versioning for your types and API is less important when the serialization format is self-describing (e.g. JSON). You can get away with relying on parser errors when the types change on one side but not the other.
Non-self-describing formats like bincode almost certainly need versioning and some protocol help. Because the serialized form can easily be misinterpreted as valid when deserializing. Especially when the API is subject to change.
After some time, created new crate called API, shared for both client and server. It features grow, so also moved there some serialization tools. Currently, mod for the shared struct that implements user registration Request looks like that. Data there contain header and JSON. So I have one interface for all applications using it - with reverse parsing tools build-in.
Not sure that everything fine yet, but I'm working on optimization / standardization by the way. The separated crate is only one right solution as the latest conclusion.