# Queriers

# Pre-requisite Readings

# Querier type

The querier type defined in the Cosmos SDK specifies the typical structure of a querier function:

Copy package types import abci "github.com/tendermint/tendermint/abci/types" // Type for querier functions on keepers to implement to handle custom queries type Querier = func(ctx Context, path []string, req abci.RequestQuery) (res []byte, err Error)

Let us break it down:

  • The path is an array of strings that contains the type of the query, and that can also contain query arguments. See queries for more information.
  • The req itself is primarily used to retrieve arguments if they are too large to fit in the path. This is done using the Data field of req.
  • The Context contains all the necessary information needed to process the query, as well as a cache-wrapped copy of the latest state. It is primarily used by the keeper to access the state.
  • The result res returned to baseapp, marhsalled using the application's codec.

# Implementation of a module queriers

Module queriers are typically implemented in a ./internal/keeper/querier.go file inside the module's folder. The module manager is used to add the module's queriers to the application's queryRouter via the NewQuerier() method. Typically, the manager's NewQuerier() method simply calls a NewQuerier() method defined in keeper/querier.go, which looks like the following:

Copy func NewQuerier(keeper Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { switch path[0] { case QueryType1: return queryType1(ctx, path[1:], req, keeper) case QueryType2: return queryType2(ctx, path[1:], req, keeper) default: return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint: %s", types.ModuleName, path[0]) } } }

This simple switch returns a querier function specific to the type of the received query. At this point of the query lifecycle, the first element of the path (path[0]) contains the type of the query. The following elements are either empty or contain arguments needed to process the query.

The querier functions themselves are pretty straighforward. They generally fetch a value or values from the state using the keeper. Then, they marshall the value(s) using the codec and return the []byte obtained as result.

For a deeper look at queriers, see this example implementation of a querier function (opens new window) from the nameservice tutorial.

# Next

Learn about BeginBlocker and EndBlocker