feat(gRPC)!: improve client ergonomics & read-mask discoverability - #1147
feat(gRPC)!: improve client ergonomics & read-mask discoverability#1147DaughterOfMars wants to merge 26 commits into
Conversation
|
Overall not sure if this PR is really worth it, just providing |
I think it's a pretty big usability increase, if not for the extra helper fns than definitely for the read mask discoverability. Before you basically had no way to know what read masks to use other than reading the doc. Now it's implicit. |
|
Thank you very much for all the improvements on the grpc client. I don't want to be picky, but I think the scope of this PR is way too big. There are so many changes that deserve their own PRs and discussions. I think we should rather create a feature branch and have scoped PRs for changes. What I wouldn't do is to double the API surface with the new "masked" functions. Improvements in mask discoverability are welcome, but we should avoid doubling the API surface just because of an Option. Users should think about the mask they pass, to adapt it to the information they really need, because it reduces the network bandwidth and also the resource consumption on the server side. |
I could split this into two PRs, but regardless I do believe both changes should happen. It's no cost to have extra functions that make calling the API easier for users. Using the masks is a power-user feature, IMO, regardless of this PR. |
Follow-up to the initial gRPC client landing (#1062). This PR sharpens the
high-level Rust gRPC API around two recurring rough edges — every read method
having to take an
Option<ReadMask>, and callers having to know by conventionwhich
XFieldnamespace pairs with which method — and adds a handful ofexamples that exercise the result.
Summary
_maskedvariant.
client.get_objects(refs)uses the canonical default mask;client.get_objects_masked(refs, mask)takes a mask directly (noOption, no wrapper). Applied to all 17 masked methods acrossget_objects/get_objects_with_versions/get_transactions/get_service_info/get_epoch/get_checkpoint_*/stream_checkpoints*/
list_owned_objects/list_dynamic_fields/get_coins/simulate_transaction(s)/execute_transaction(s).XField(e.g.ObjectField,TransactionField,EpochField, …) is now a typedCow<'static, str>newtype instead of a bag of&strconsts, and eachmasked endpoint accepts a paired
XReadMask(ObjectReadMask,TransactionReadMask, …) viaimpl Into<…>. Call sites become:ReadMask::from(…)wrapper. PassingTransactionField::EFFECTStoget_objects_maskedis now a compile error. Pre-computed mask constantsin
read_masks::*still flow through viaFrom<&'static str>/From<String>escape hatches on each scoped mask.Client::get_coins(_masked)plusGetCoinsQuerybuilder instate/coins.rs— paginated coin listing with optionalStructTagfilter, returning
iota_types::framework::Coinitems (protoObject→SDK
Coinconversion happens internally).CheckpointResponseaccessors refactored to return SDK types directly.response.summary()/.signature()/.contents()now yield thedeserialized SDK types; the proto variants are renamed to
_grpc(
summary_grpc, etc.). Same pattern as theexecuted_transactions/executed_transactions_grpcsplit.Client:Client::new_localnet(),new_devnet(),new_testnet(),new_mainnet()plus pub-crate hostconstants.
iota-sdk'sgrpcfeature. Previouslyenabling
iota-sdk/grpcpulled iniota-grpc-clientwithdefault-features = false, soClient::new_testnet()failed at runtimewith
"HTTPS requires the tls-ring feature". Thegrpcfeature nowforwards
tls-ring+tls-native-roots.crates/iota-sdk/examples/:chain_id_grpc,get_object_grpc,owned_objects_grpc,stream_checkpoints_grpc— the last has no GraphQL counterpart andexists specifically to showcase the streaming RPC.
Migration
This is a breaking change to the gRPC client surface. The mechanical
rewrite at call sites:
get_objects(refs, None)get_objects(refs)get_objects(refs, Some(ReadMask::from(ObjectField::BCS)))get_objects_masked(refs, ObjectField::BCS)get_objects(refs, Some(ReadMask::from(&[ObjectField::BCS, ObjectField::REFERENCE])))get_objects_masked(refs, [ObjectField::BCS, ObjectField::REFERENCE])cp.summary()?.summary()?cp.summary()?cp.signature()?.signature()?cp.signature()?cp.contents()?.contents()?cp.contents()?XField::Yused to evaluate to&'static str; it's now anXFieldstruct. Use
.as_str()if you need the underlying path string.ReadMask<'_>is retained as a low-level string holder for advancedcomposition but is no longer accepted by client methods directly — pass a
scoped mask (or a
&strfor the escape hatch) instead.