Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

go-swagger example from source #3

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,9 @@ Add support for cosmos and cosmos-sdk chains
- The core functionality of chains like Osmosis and Thorchain is identical to Cosmos
- We can write the Cosmos SDK implementation once, and provide mechanisms to inject chain specific behavior (additional protos, support for custom messages and event logs, custom API routes etc)

# Swagger

- Install go-swagger (homebrew works for osx)
- Create vendor package by running: `go mod vendor`
- Generate swagger spec from source by running: `swagger generate spec -o ./swagger.yaml --scan-models`
- Start swagger docs server: `swagger serve -F=swagger swagger.yaml`
1 change: 1 addition & 0 deletions cmd/cosmos/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
_ "github.com/shapeshift/unchained-cosmos/docs/cosmos"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to import this in main even if its unused so that go-swagger can see it

"github.com/shapeshift/unchained-cosmos/server/rest"
"github.com/shapeshift/unchained-cosmos/service"
log "github.com/sirupsen/logrus"
Expand Down
16 changes: 16 additions & 0 deletions docs/cosmos/docs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Package classification Cosmos Unchained.
//
// Documentation of our Cosmos Unchained API.
//
// Schemes: http
// BasePath: /
// Version: 1.0.0
// Host: localhost:1660
//
// Consumes:
// - application/json
//
// Produces:
// - application/json
// swagger:meta
package docs
67 changes: 67 additions & 0 deletions docs/cosmos/swagger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package docs

import (
"github.com/shapeshift/unchained-cosmos/service"
)

// swagger:route GET /account/{pubkey} account-tag accountEndpointId
Copy link
Contributor Author

@elmutt elmutt Dec 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These can live anywhere that is a child of the main.go.

It could be placed next to each endpoint but the example I was looking at kept it in this separate file.

It is a bit cleaner this way but I dont have much preference

// Gets account information
// responses:
// 200: accountResponse
// 500: accountResponseError

// Account response contains informations about account (balance, sequence, etc)
// swagger:response accountResponse
type accountResponseWrapper struct {
// in:body
Body service.Account
}

// Account response error
// swagger:response accountResponseError
type accountResponseErrorWrapper struct {
// in:body
Body struct {
// Example: error reading account for cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
Error string `json:"error"`
}
}

// Account url param to specify pubkey (address) to get account info (balance, sequence, etc)
// swagger:parameters accountEndpointId
type accountParams struct {
// Pubkey (address) to get account details for
// in:path
Pubkey string `json:"pubkey"`
}

// swagger:route GET /account/{pubkey}/txs txs-tag txsEndpointId
// Handles getting TX History for an account by pubkey (address)
// responses:
// 200: txsResponse
// 500: txsResponseError

// Tsxxs response contains tx history
// swagger:response txsResponse
type txsResponseWrapper struct {
// in:body
Body service.TxHistory
}

// Param to specify pubkey (address) for tx history
// swagger:parameters txsEndpointId
type txsParams struct {
// Pubkey (address) to get tx history for
// in:path
Pubkey string `json:"pubkey"`
}

// Txs response error
// swagger:response txsResponseError
type txsResponseErrorWrapper struct {
// in:body
Body struct {
// Example: error reading txhistory for recipient cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
Error string `json:"error"`
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ require (
github.com/eager7/dogd v0.0.0-20200427085516-2caf59f59dbb // indirect
github.com/eager7/dogutil v0.0.0-20200427040807-200e961ba4b5 // indirect
github.com/ethereum/go-ethereum v1.10.4 // indirect
github.com/felixge/httpsnoop v1.0.1 // indirect
github.com/gcash/bchd v0.17.1 // indirect
github.com/gcash/bchutil v0.0.0-20201025062739-fc759989ee3e // indirect
github.com/google/uuid v1.3.0 // indirect
Expand Down Expand Up @@ -59,6 +60,7 @@ require (
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/snappy v0.0.3 // indirect
github.com/google/btree v1.0.0 // indirect
github.com/gorilla/handlers v1.5.1
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
Expand Down
7 changes: 6 additions & 1 deletion server/rest/rest.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"net/http"

"github.com/gorilla/handlers"
"github.com/gorilla/mux"
"github.com/shapeshift/unchained-cosmos/service"

Expand Down Expand Up @@ -44,15 +45,19 @@ func (s *UnchainedRestServer) start() {
router.StrictSlash(true)

router.HandleFunc("/account/{pubkey}", s.GetAccount)

router.HandleFunc("/account/{pubkey}/txs", s.GetTxHistory)

listenAddr := s.config.RestListenAddr
if listenAddr == "" {
listenAddr = "localhost:1660"
}

credentials := handlers.AllowCredentials()
methods := handlers.AllowedMethods([]string{"*"})
origins := handlers.AllowedOrigins([]string{"*"})
log.Infof("invoking ListenAndServe on %s", listenAddr)
log.Errorf("ListenAndServe returned: %s", http.ListenAndServe(listenAddr, router))
log.Errorf("ListenAndServe returned: %s", http.ListenAndServe(listenAddr, handlers.CORS(credentials, methods, origins)(router)))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to add cors stuff so calls from the swagger doc server would work

}

func writeError(writer http.ResponseWriter, errRes ErrorResponse) error {
Expand Down
23 changes: 15 additions & 8 deletions service/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,25 @@ import (
)

type Account struct {
Pubkey string `json:"pubkey"`
AccountNumber uint64 `json:"accountNumber,string"`
Sequence uint64 `json:"sequence,string"`
Balance string `json:"balance"`
Tokens []TokenAmount `json:"tokens"`
Delegations []Delegation `json:"delegations"`
// Example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is how example values are populated in go-swagger

Pubkey string `json:"pubkey"`
// Example: 9810
AccountNumber uint64 `json:"accountNumber,string"`
// Example: 43211
Sequence uint64 `json:"sequence,string"`
// Example: 14250
Balance string `json:"balance"`
Tokens []TokenAmount `json:"tokens"`
Delegations []Delegation `json:"delegations"`
}

type Delegation struct {
// Example: cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf
Validator string `json:"validator"`
Amount string `json:"amount"`
Shares string `json:"shares"`
// Example: 45531
Amount string `json:"amount"`
// Example: 86544
Shares string `json:"shares"`
}

func (c *CosmosService) readDelegations(address string) ([]stakingtypes.DelegationResponse, error) {
Expand Down
81 changes: 56 additions & 25 deletions service/txhistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ type TxAction interface {
GetType() string
}
type BaseTxAction struct {
// Example: transfer
Type string `json:"type"`
}

Expand All @@ -70,60 +71,90 @@ func (action BaseTxAction) GetType() string {

type TransferTxAction struct {
BaseTxAction
// Example: cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf
FromAddress string `json:"fromAddress"`
ToAddress string `json:"toAddress"`
Asset string `json:"asset"`
Amount string `json:"amount"`
// Example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
ToAddress string `json:"toAddress"`
// Example: utatom
Asset string `json:"asset"`
// Example: 71478
Amount string `json:"amount"`
}

type DelegateTxAction struct {
BaseTxAction
// Example: cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf
Validator string `json:"validator"`
Amount string `json:"amount"`
// Example: 21478
Amount string `json:"amount"`
}

type ReDelegateTxAction struct {
BaseTxAction
// Example: cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf
SourceValidator string `json:"sourceValidator"`
DestValidator string `json:"destValidator"`
Amount string `json:"amount"`
// Example: cosmosvaloper14lultfckehtszvzw4ehu0apvsr77afvyju5zzy
DestValidator string `json:"destValidator"`
// Example: 46012
Amount string `json:"amount"`
}

type WithdrawRewardsTxAction struct {
BaseTxAction
// Example: cosmosvaloper14lultfckehtszvzw4ehu0apvsr77afvyju5zzy
Validator string `json:"validator"`
Asset string `json:"asset"`
Amount string `json:"amount"`
// Example: uatom
Asset string `json:"asset"`
// Example: 42069
Amount string `json:"amount"`
}

type IBCTransferTxAction struct {
BaseTxAction
// Example: cosmos1x54ltnyg88k0ejmk8ytwrhd3ltm84xehrnlslf
FromAddress string `json:"fromAddress"`
ToAddress string `json:"toAddress"`
// Example: cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf
ToAddress string `json:"toAddress"`
}

// Unchained API Historical Tx Model
type HistTx struct {
Type string `json:"type"`
TxID string `json:"txid"`
Status string `json:"status"`
From string `json:"from,omitempty"`
To string `json:"to,omitempty"`
BlockHeight int64 `json:"blockHeight"`
Index uint `json:"index"`
Confirmations int64 `json:"confirmations"`
Timestamp int64 `json:"timestamp"`
Value string `json:"value,omitempty"`
Memo string `json:"memo,omitempty"`
Fee string `json:"fee"`
FeeAsset string `json:"feeAsset"`
GasWanted string `json:"gasWanted"`
GasUsed string `json:"gasUsed"`
Actions []TxAction `json:"actions"`
// Example: send
Type string `json:"type"`
// Example: B3127187CA99D7F2C0BAE4FA26512F204B6CEC80AD3C3AE514B8D3A77CD99B43
TxID string `json:"txid"`
// Example: confirmed
Status string `json:"status"`
// Example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
From string `json:"from,omitempty"`
// Example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
To string `json:"to,omitempty"`
// Example: 34534
BlockHeight int64 `json:"blockHeight"`
// Example: 678678
Index uint `json:"index"`
// Example: 24346
Confirmations int64 `json:"confirmations"`
// Example: 1639598717717
Timestamp int64 `json:"timestamp"`
// Example: 866543
Value string `json:"value,omitempty"`
// Example: This is a memo
Memo string `json:"memo,omitempty"`
// Example: 4223
Fee string `json:"fee"`
// Example: 'uatom'
FeeAsset string `json:"feeAsset"`
// Example: 42345
GasWanted string `json:"gasWanted"`
// Example: 383312
GasUsed string `json:"gasUsed"`
Actions []TxAction `json:"actions"`
}

type TxHistory struct {
// TODO - pagination
// Example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e
Pubkey string `json:"pubkey"`
Txs []HistTx `json:"txs"`
}
Expand Down
4 changes: 3 additions & 1 deletion service/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ type JsonRpcMsg struct {

// Unchained API Types
type TokenAmount struct {
Denom string `json:"denom"`
// Example: uatom
Denom string `json:"denom"`
// Example: 420
Amount string `json:"amount"`
}
Loading