Skip to main content

Overview

Cosmos SDK provides a REST API server that exposes blockchain queries and transaction broadcasting over HTTP. It uses gRPC-Gateway to automatically generate REST endpoints from gRPC service definitions.

API Server Setup

Server Configuration

import "github.com/cosmos/cosmos-sdk/server/api"

type Config struct {
    Enable             bool   `mapstructure:"enable"`
    Swagger            bool   `mapstructure:"swagger"`
    Address            string `mapstructure:"address"`
    MaxOpenConnections int    `mapstructure:"max-open-connections"`
    RPCReadTimeout     uint   `mapstructure:"rpc-read-timeout"`
    RPCWriteTimeout    uint   `mapstructure:"rpc-write-timeout"`
    RPCMaxBodyBytes    uint   `mapstructure:"rpc-max-body-bytes"`
    EnableUnsafeCORS   bool   `mapstructure:"enabled-unsafe-cors"`
}

func DefaultConfig() *Config {
    return &Config{
        Enable:             true,
        Swagger:            false,
        Address:            "tcp://0.0.0.0:1317",
        MaxOpenConnections: 1000,
        RPCReadTimeout:     10,
        RPCWriteTimeout:    10,
        RPCMaxBodyBytes:    1000000,
        EnableUnsafeCORS:   false,
    }
}
Location: server/config/config.go

Starting the API Server

import (
    "github.com/cosmos/cosmos-sdk/server/api"
    "github.com/cosmos/cosmos-sdk/server"
)

func StartAPIServer(
    ctx *server.Context,
    clientCtx client.Context,
    cfg config.APIConfig,
) (*api.Server, error) {
    apiSrv := api.New(clientCtx, ctx.Logger.With("module", "api-server"))
    
    // Register gRPC-Gateway routes
    app.RegisterGRPCGatewayRoutes(clientCtx, apiSrv.Router)
    
    // Register Tendermint/CometBFT routes
    cmtservice.RegisterGRPCGatewayRoutes(clientCtx, apiSrv.Router)
    
    // Register tx routes
    authtx.RegisterGRPCGatewayRoutes(clientCtx, apiSrv.Router)
    
    // Enable swagger documentation
    if cfg.Swagger {
        apiSrv.Router.Handle("/swagger", http.HandlerFunc(
            func(w http.ResponseWriter, r *http.Request) {
                // Serve swagger UI
            },
        ))
    }
    
    // Start server
    return apiSrv, apiSrv.Start(cfg)
}
Location: server/api/server.go

gRPC-Gateway Integration

Registering Routes

import (
    "github.com/grpc-ecosystem/grpc-gateway/runtime"
    "github.com/cosmos/cosmos-sdk/client"
)

func RegisterGRPCGatewayRoutes(
    clientCtx client.Context,
    mux *runtime.ServeMux,
) {
    // Register bank module routes
    banktypes.RegisterQueryHandlerClient(
        context.Background(),
        mux,
        banktypes.NewQueryClient(clientCtx),
    )
    
    // Register staking module routes
    stakingtypes.RegisterQueryHandlerClient(
        context.Background(),
        mux,
        stakingtypes.NewQueryClient(clientCtx),
    )
    
    // Register other modules...
}

Auto-Generated REST Endpoints

REST endpoints are automatically generated from gRPC service definitions:
service Query {
  // Maps to: GET /cosmos/bank/v1beta1/balances/{address}/by_denom
  rpc Balance(QueryBalanceRequest) returns (QueryBalanceResponse) {
    option (google.api.http).get = "/cosmos/bank/v1beta1/balances/{address}/by_denom";
  }
  
  // Maps to: GET /cosmos/bank/v1beta1/balances/{address}
  rpc AllBalances(QueryAllBalancesRequest) returns (QueryAllBalancesResponse) {
    option (google.api.http).get = "/cosmos/bank/v1beta1/balances/{address}";
  }
  
  // Maps to: GET /cosmos/bank/v1beta1/supply
  rpc TotalSupply(QueryTotalSupplyRequest) returns (QueryTotalSupplyResponse) {
    option (google.api.http).get = "/cosmos/bank/v1beta1/supply";
  }
}

REST API Usage

Querying Balances

# Get single balance
curl http://localhost:1317/cosmos/bank/v1beta1/balances/cosmos1.../by_denom?denom=stake

# Response
{
  "balance": {
    "denom": "stake",
    "amount": "1000000"
  }
}

# Get all balances
curl http://localhost:1317/cosmos/bank/v1beta1/balances/cosmos1...

# Response
{
  "balances": [
    {
      "denom": "stake",
      "amount": "1000000"
    },
    {
      "denom": "token",
      "amount": "500000"
    }
  ],
  "pagination": {
    "next_key": null,
    "total": "2"
  }
}

Pagination in REST

# Request with pagination
curl "http://localhost:1317/cosmos/bank/v1beta1/balances/cosmos1...?pagination.limit=10&pagination.offset=0"

# Using page key
curl "http://localhost:1317/cosmos/bank/v1beta1/balances/cosmos1...?pagination.key=base64_encoded_key"

# Response includes pagination info
{
  "balances": [...],
  "pagination": {
    "next_key": "base64_encoded_next_key",
    "total": "100"
  }
}

Broadcasting Transactions

# Broadcast a signed transaction
curl -X POST http://localhost:1317/cosmos/tx/v1beta1/txs \
  -H "Content-Type: application/json" \
  -d '{
    "tx_bytes": "base64_encoded_tx",
    "mode": "BROADCAST_MODE_SYNC"
  }'

# Response
{
  "tx_response": {
    "height": "0",
    "txhash": "ABC123...",
    "codespace": "",
    "code": 0,
    "data": "",
    "raw_log": "[]",
    "logs": [],
    "info": "",
    "gas_wanted": "200000",
    "gas_used": "0",
    "tx": null,
    "timestamp": ""
  }
}

Simulating Transactions

# Simulate transaction before broadcasting
curl -X POST http://localhost:1317/cosmos/tx/v1beta1/simulate \
  -H "Content-Type: application/json" \
  -d '{
    "tx_bytes": "base64_encoded_tx"
  }'

# Response
{
  "gas_info": {
    "gas_wanted": "0",
    "gas_used": "123456"
  },
  "result": {
    "data": "",
    "log": "",
    "events": []
  }
}

Query Transaction by Hash

# Get transaction by hash
curl http://localhost:1317/cosmos/tx/v1beta1/txs/ABC123...

# Response
{
  "tx": {
    "body": {
      "messages": [...],
      "memo": "",
      "timeout_height": "0",
      "extension_options": [],
      "non_critical_extension_options": []
    },
    "auth_info": {...},
    "signatures": [...]
  },
  "tx_response": {
    "height": "12345",
    "txhash": "ABC123...",
    "code": 0,
    "logs": [...],
    "gas_wanted": "200000",
    "gas_used": "123456"
  }
}

Custom REST Endpoints

Legacy REST Registration

For custom endpoints not covered by gRPC-Gateway:
import (
    "github.com/gorilla/mux"
    "github.com/cosmos/cosmos-sdk/client"
)

// Register custom REST routes
func RegisterRoutes(
    clientCtx client.Context,
    r *mux.Router,
) {
    r.HandleFunc(
        "/custom/endpoint",
        customQueryHandlerFn(clientCtx),
    ).Methods("GET")
}

func customQueryHandlerFn(clientCtx client.Context) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Parse query parameters
        vars := mux.Vars(r)
        param := vars["param"]
        
        // Query state
        queryClient := types.NewQueryClient(clientCtx)
        res, err := queryClient.CustomQuery(
            r.Context(),
            &types.QueryRequest{Param: param},
        )
        if err != nil {
            rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
            return
        }
        
        // Write response
        rest.PostProcessResponse(w, clientCtx, res)
    }
}

OpenAPI/Swagger Documentation

Enabling Swagger UI

import (
    "github.com/rakyll/statik/fs"
    _ "github.com/cosmos/cosmos-sdk/client/docs/statik" // statik files
)

func RegisterSwagger(apiSrv *api.Server) {
    statikFS, err := fs.New()
    if err != nil {
        panic(err)
    }
    
    staticServer := http.FileServer(statikFS)
    apiSrv.Router.PathPrefix("/swagger/").Handler(staticServer)
}
Access Swagger UI at: http://localhost:1317/swagger/

Generating OpenAPI Specs

# Generate OpenAPI specifications from proto files
make proto-swagger-gen

# Combine all specs into single file
cd client/docs
statik -src=./swagger-ui -dest=. -f

CORS Configuration

import "github.com/rs/cors"

func setupCORS(handler http.Handler, enableUnsafeCORS bool) http.Handler {
    if enableUnsafeCORS {
        // Allow all origins (development only!)
        return cors.New(cors.Options{
            AllowedOrigins: []string{"*"},
            AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
            AllowedHeaders: []string{"*"},
        }).Handler(handler)
    }
    
    // Production CORS settings
    return cors.New(cors.Options{
        AllowedOrigins: []string{
            "https://yourdomain.com",
        },
        AllowedMethods: []string{"GET", "POST"},
        AllowedHeaders: []string{"Content-Type"},
    }).Handler(handler)
}

Client Usage Examples

JavaScript/TypeScript

import axios from 'axios';

const API_URL = 'http://localhost:1317';

// Query balance
async function getBalance(address: string, denom: string) {
  const response = await axios.get(
    `${API_URL}/cosmos/bank/v1beta1/balances/${address}/by_denom`,
    { params: { denom } }
  );
  return response.data.balance;
}

// Query all balances with pagination
async function getAllBalances(address: string, limit: number = 100) {
  let allBalances = [];
  let nextKey = null;
  
  do {
    const params = {
      'pagination.limit': limit.toString(),
    };
    
    if (nextKey) {
      params['pagination.key'] = nextKey;
    }
    
    const response = await axios.get(
      `${API_URL}/cosmos/bank/v1beta1/balances/${address}`,
      { params }
    );
    
    allBalances = allBalances.concat(response.data.balances);
    nextKey = response.data.pagination?.next_key;
  } while (nextKey);
  
  return allBalances;
}

// Broadcast transaction
async function broadcastTx(txBytes: string) {
  const response = await axios.post(
    `${API_URL}/cosmos/tx/v1beta1/txs`,
    {
      tx_bytes: txBytes,
      mode: 'BROADCAST_MODE_SYNC'
    }
  );
  return response.data.tx_response;
}

Python

import requests
import base64

API_URL = "http://localhost:1317"

def get_balance(address: str, denom: str):
    response = requests.get(
        f"{API_URL}/cosmos/bank/v1beta1/balances/{address}/by_denom",
        params={"denom": denom}
    )
    response.raise_for_status()
    return response.json()["balance"]

def broadcast_tx(tx_bytes: bytes):
    tx_bytes_b64 = base64.b64encode(tx_bytes).decode('utf-8')
    response = requests.post(
        f"{API_URL}/cosmos/tx/v1beta1/txs",
        json={
            "tx_bytes": tx_bytes_b64,
            "mode": "BROADCAST_MODE_SYNC"
        }
    )
    response.raise_for_status()
    return response.json()["tx_response"]
  • gRPC - gRPC server implementation
  • Client - Client context and tools
  • Types - Data types for queries and transactions

Build docs developers (and LLMs) love