Start by creating the ./x/nameservice/querier.go
file. This is the place to define which queries against application state users will be able to make. In our nameservice
we want to expose two:
resolve
: This takes aname
and returns thevalue
that is stored by thenameservice
. This is similar to a DNS query.whois
: This takes aname
and returns theprice
,value
, andowner
of the name. Used for figuring out how much names cost when you want to buy them.
Start by defining the NewQuerier
function which acts a sub-router for queries to this module (similar to our NewHandler
function). Note that because we don't have an interface similar to Msg
for queries we need to manually define our switch statement cases (they can't be pulled off of the query .Name()
function):
package nameservice
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
// query endpoints supported by the governance Querier
const (
QueryResolve = "resolve"
QueryWhois = "whois"
)
// NewQuerier is the module level router for state queries
func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) {
switch path[0] {
case QueryResolve:
return queryResolve(ctx, path[1:], req, keeper)
case QueryWhois:
return queryWhois(ctx, path[1:], req, keeper)
default:
return nil, sdk.ErrUnknownRequest("unknown nameservice query endpoint")
}
}
}
Now that the router is defined, define the inputs and responses for each query:
// nolint: unparam
func queryResolve(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
name := path[0]
value := keeper.ResolveName(ctx, name)
if value == "" {
return []byte{}, sdk.ErrUnknownRequest("could not resolve name")
}
return []byte(value), nil
}
// nolint: unparam
func queryWhois(ctx sdk.Context, path []string, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) {
name := path[0]
whois := Whois{}
whois.Value = keeper.ResolveName(ctx, name)
whois.Owner = keeper.GetOwner(ctx, name)
whois.Price = keeper.GetPrice(ctx, name)
bz, err2 := codec.MarshalJSONIndent(keeper.cdc, whois)
if err2 != nil {
panic("could not marshal result to JSON")
}
return bz, nil
}
// Whois represents a name -> value lookup
type Whois struct {
Value string `json:"value"`
Owner sdk.AccAddress `json:"owner"`
Price sdk.Coins `json:"price"`
}
Notes on the above code:
- Here our
Keeper
's' getters and setters come into heavy use. When building any other applications that use this module you may need to go back and define more getters/setters to access the pieces of state you need. - If your application needs some custom response types (
Whois
here), define them in this file.