Introduce Blockchain API of Cosmos SDK
Tags: go, blockchain
Published: 2020-04-01 05:11:20

This post explains how to use and start Cosmos SDK - blockchain api.

# What is Cosmos
Cosmos is a blockchain platform which is provided by Cosmos Network (Tendermint Inc).
- https://cosmos.network/

# What can be done by Cosmos SDK
With using Cosmos SDK, you can easily develop your product like a REST API server.
Cosmos SDK provides API which is written by Go language.

Actually, I could develop a REST API server by two days implementation in DeFi hackathon of San Francisco Blockchain Week 2019.

The following is a repository which I made in the hackathon.
- https://github.com/tashxii/bor-bc-go

# Build a REST API server
Starting point is to clone the following repository.
- https://github.com/cosmos/sdk-tutorials/tree/master/nameservice

You can create REST API server and also store your own data in Cosmos Blockchain network.

I will introduce the important points when you develop a REST API server with using Cosmos SDK.

## rest.go (x/borsevice/client/rest)
rest.go is an entry point of the definition of REST API.

You can define the corresponding of api url and actual function.
- mux.Router is a router object of Cosmos SDK
- you can set a combination of an api url and a function by 
"HandleFunc"
- you can set a method type like "GET", "POST" and so on by "Methods"

```go
// RegisterRoutes - Central function to define routes that get registered by the main application
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, storeName string) {
	r.HandleFunc(fmt.Sprintf("/%s/prizes", storeName), namesHandler(cliCtx, storeName)).Methods("GET")
	r.HandleFunc(fmt.Sprintf("/%s/prizes", storeName), initPrizeHandler(cliCtx)).Methods("POST")
	r.HandleFunc(fmt.Sprintf("/%s/prizes", storeName), setPrizeHandler(cliCtx)).Methods("PUT")
	r.HandleFunc(fmt.Sprintf("/%s/prizes/{%s}", storeName, restName), resolveNameHandler(cliCtx, storeName)).Methods("GET")
	r.HandleFunc(fmt.Sprintf("/%s/prizes/{%s}/whois", storeName, restName), whoIsHandler(cliCtx, storeName)).Methods("GET")
	r.HandleFunc(fmt.Sprintf("/%s/prizes", storeName), deletePrizeHandler(cliCtx)).Methods("DELETE")
}
```
## Define JSON format of a request
"rest" module - which can be import from "github.com/cosmos/cosmos-sdk/types/rest" - provides utilized function.

For example, you can see the use-case how to define JSON response and read and convert your own model in the following code.

- "rest.BaseReq" struct is a base struct which you can add your own properties in JSON format.
- "rest.ReadRESTReq" function can read HTTP request and convert a JSON request to in-memory object of your own struct.

```go
type setPrizeReq struct {
	BaseReq       rest.BaseReq `json:"base_req"`
	Name          string       `json:"name"`
	Value         string       `json:"value"`
	Owner         string       `json:"owner"`
	Account       string       `json:"account"`
	Passphrase    string       `json:"passphrase"`
	Sequence      int64        `json:"sequence"`
	AccountNumber int64        `json:"accoutNumber"`
}

func setPrizeHandler(cliCtx context.CLIContext) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var req setPrizeReq
		if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) {
			rest.WriteErrorResponse(w, http.StatusBadRequest, "failed to parse request")
			return
		}
	(snip)
```


## Write your own process of Cosmos blockchain
After reading JSON request, you can implement your own process of Cosmos blockchain.

The following code is an example to do create a transaction and sign it and then broadcast to the blockchain network.

```go
// WriteGenerateStdTxResponse writes response for the generate only mode.
func WriteGenerateStdTxResponse(w http.ResponseWriter, cliCtx context.CLIContext,
	br rest.BaseReq, msgs []sdk.Msg, req setPrizeReq) {
	gasAdj, ok := rest.ParseFloat64OrReturnBadRequest(w, br.GasAdjustment, flags.DefaultGasAdjustment)
	if !ok {
		return
	}

	simAndExec, gas, err := flags.ParseGas(br.Gas)
	if err != nil {
		rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
		return
	}

	txBldr := types.NewTxBuilder(
		utils.GetTxEncoder(cliCtx.Codec), br.AccountNumber, br.Sequence, gas, gasAdj,
		br.Simulate, br.ChainID, br.Memo, br.Fees, br.GasPrices,
	)

	if br.Simulate || simAndExec {
		if gasAdj < 0 {
			rest.WriteErrorResponse(w, http.StatusBadRequest, errInvalidGasAdjustment.Error())
			return
		}

		txBldr, err = utils.EnrichWithGas(txBldr, cliCtx, msgs)
		if err != nil {
			rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
			return
		}

		if br.Simulate {
			rest.WriteSimulationResponse(w, cliCtx.Codec, txBldr.Gas())
			return
		}
	}

	stdMsg, err := txBldr.BuildSignMsg(msgs)
	if err != nil {
		rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
		return
	}

	transactionStdTx := types.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)

	// Create cdc
	cdc := cliCtx.Codec

	// Sign Tx
	signedStdTx, err := signTx(cdc, transactionStdTx, req.Account, req.Account, req.Passphrase, req.Sequence, req.AccountNumber)
	if err != nil {
		rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
		return
	}

	// TODO Broadcast Tx
	err = broadcastTx(cdc, signedStdTx)
	if err != nil {
		rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
		return
	}
	output, err := cliCtx.Codec.MarshalJSON(signedStdTx)
	if err != nil {
		rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
		return
	}

	w.Header().Set("Content-Type", "application/json")
	if _, err := w.Write(output); err != nil {
		log.Printf("could not write response: %v", err)
	}

	return
}
```

### Create a transaction
Cosmos SDK provides a builder of transaction called as "types.TxBuilder".
- you can create a builder by "types.NewTxBuilder" function.
- a transaction object can be generated by "txBldr.BuildSignMsg" function.

### Sign and broadcast a transaction
"signTx" & "broadcast" functions are not provided as Cosmos REST API.
They are reused from Cosmos CLI SDK and converted by me to fit REST API in the hackathon.

If you have further interesting about these two functions.
Please see the following codes.
- https://github.com/tashxii/bor-bc-go/blob/dd3258bd338df23a65432cd4eed2007091d763a9/x/borservice/client/rest/extend_rest.go#L95-L156