The resolution api can safely be integrated into the omnigraph because the protocol acceleration plugin is a hard dependency of running the omnigraph plugin. so we don't have to worry about any conditional api availability in this case.
We want to expose
Domain.records
Account.primaryNames
with an ergonomic graphql api. A major decision here is to not use the connection pattern because we want records to be trivially accessible. Another major decision is to not expose the acceleration metadata nor the trace as part of this api, which avoids an additional hierarchy in the tree.
here's one suggestion:
entity ResolverRecords {
name: String // nullable name record
texts(keys: [String!]): [TextRecord!]! // array of text records
addresses(coinTypes: [CoinType!]): [AddressRecord!]! // array of address record
// TODO: all of the other possible fields like contenthash, etc
}
entity TextRecord {
key: String!
value: String // nullable
}
entity AddressRecord {
coinType: CoinType!
address: String // nullable, can be any address, not just evm
}
query Records($name: Name!) {
domain(by: { name: $name }) {
# simple
records {
name
texts { key value }
addresses { coinType address }
}
# disabled acceleration
records(accelerate: False) { ... }
# specific keys
records {
texts(keys: ["description"]) { key value }
}
}
}
This differs from the HTTP in that instead of returning a map of text records, it returns an array which fits better into the GraphQL type system. If we were to return a map with arbitrary keys, we would have to use a JSON scalar (ResolverRecords.texts: JSONObject!, ResolverRecords.addresses: JSONObject!) and we'd lose the additional typing on the key/value and coinType/address properties. Returning an array is simplest and users can simply keyBy or .find when rendering specific fields.
Domain.records should accept an accelerate?: Boolean input that defaults to true. Because we also specify the text(keys: ["description"]) at the ResolverRecords.texts level (and likewise for ResolverRecords.addresses we'll probably have to introspect the query at runtime to derive the keys/addresses that the users wishes to resolve.
we'll also want to inject the results of the indexing status and canAccelerate middlewares into the pothos context so that the resolver for Domain.records can access context.canAccelerate for example for use with resolveForward and resolveReverse.
For Primary Names, we'll follow a similar pattern
entity PrimaryName {
coinType: CoinType!
name: Name!
}
query PrimaryNames($address: Address!) {
account(by: { address: $address }) {
// all primary names
primaryNames { coinType name }
// filtered by set
primaryNames(coinTypes: [60]) { coinType name }
// can also disable acceleration
primaryNames(accelerate: False, coinTypes: [60]) { coinType name }
}
}
Let's also refactor the Resolution API's Primary Names handlers to accept not chain ID but coin type and force clients to provide the exact cointypes they want instead of deriving them from chainId, which was confusing as hell. So this will also affect the http version of this api and induce a breaking change.
If we wanted to expose the acceleration meta, we would probably want to scope things like so.
entity AccelerationMeta {
requested: Boolean!
attempted: Boolean!
}
query ResolveRecords($name: Name!) {
domain(by: {name: $name}) {
records {
records { name texts { key value } addresses { coinType address } }
acceleration { requested attempted }
trace
}
}
}
which is clearly less pleasing. we could flatten the acceleration/trace meta into the ResolverRecords type BUT this breaks when we talk about Account.primaryNames which wants to return an array, so we'd have to nest it like so
query PrimaryNames($address: Address!) {
account(by: { address: $address }) {
primaryNames {
names { coinType name }
acceleration { requested attempted }
trace
}
}
}
which again is clearly less pleasing. This format works well at the HTTP level because there's this implicit data at the top-level hierarchy where we can shove things and then use the semantic label for the values that we're returning. But in GraphQL it would read a lot better if we could use the semantic label and then get the values directly.
The resolution api can safely be integrated into the omnigraph because the protocol acceleration plugin is a hard dependency of running the omnigraph plugin. so we don't have to worry about any conditional api availability in this case.
We want to expose
Domain.recordsAccount.primaryNameswith an ergonomic graphql api. A major decision here is to not use the connection pattern because we want records to be trivially accessible. Another major decision is to not expose the acceleration metadata nor the trace as part of this api, which avoids an additional hierarchy in the tree.
here's one suggestion:
This differs from the HTTP in that instead of returning a map of text records, it returns an array which fits better into the GraphQL type system. If we were to return a map with arbitrary keys, we would have to use a JSON scalar (
ResolverRecords.texts: JSONObject!,ResolverRecords.addresses: JSONObject!) and we'd lose the additional typing on the key/value and coinType/address properties. Returning an array is simplest and users can simplykeyByor.findwhen rendering specific fields.Domain.recordsshould accept anaccelerate?: Booleaninput that defaults to true. Because we also specify thetext(keys: ["description"])at theResolverRecords.textslevel (and likewise forResolverRecords.addresseswe'll probably have to introspect the query at runtime to derive the keys/addresses that the users wishes to resolve.we'll also want to inject the results of the indexing status and canAccelerate middlewares into the pothos context so that the resolver for
Domain.recordscan accesscontext.canAcceleratefor example for use withresolveForwardandresolveReverse.For Primary Names, we'll follow a similar pattern
Let's also refactor the Resolution API's Primary Names handlers to accept not chain ID but coin type and force clients to provide the exact cointypes they want instead of deriving them from chainId, which was confusing as hell. So this will also affect the http version of this api and induce a breaking change.
If we wanted to expose the acceleration meta, we would probably want to scope things like so.
which is clearly less pleasing. we could flatten the acceleration/trace meta into the ResolverRecords type BUT this breaks when we talk about
Account.primaryNameswhich wants to return an array, so we'd have to nest it like sowhich again is clearly less pleasing. This format works well at the HTTP level because there's this implicit data at the top-level hierarchy where we can shove things and then use the semantic label for the values that we're returning. But in GraphQL it would read a lot better if we could use the semantic label and then get the values directly.