From fea0192c487d2cad187e5648d6497a8e09846e4b Mon Sep 17 00:00:00 2001 From: Sean Luther Date: Wed, 15 Dec 2021 13:32:29 -0700 Subject: [PATCH] go-swagger example from source --- README.md | 6 ++ cmd/cosmos/main.go | 1 + docs/cosmos/docs.go | 16 +++ docs/cosmos/swagger.go | 67 ++++++++++++ go.mod | 2 + server/rest/rest.go | 7 +- service/account.go | 23 ++-- service/txhistory.go | 81 +++++++++----- service/types.go | 4 +- swagger.yaml | 234 +++++++++++++++++++++++++++++++++++++++++ 10 files changed, 406 insertions(+), 35 deletions(-) create mode 100644 docs/cosmos/docs.go create mode 100644 docs/cosmos/swagger.go create mode 100644 swagger.yaml diff --git a/README.md b/README.md index 1e96cf8..8ec27d4 100644 --- a/README.md +++ b/README.md @@ -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` \ No newline at end of file diff --git a/cmd/cosmos/main.go b/cmd/cosmos/main.go index e19e1ac..cb3dfdd 100644 --- a/cmd/cosmos/main.go +++ b/cmd/cosmos/main.go @@ -6,6 +6,7 @@ import ( "os" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/shapeshift/unchained-cosmos/docs/cosmos" "github.com/shapeshift/unchained-cosmos/server/rest" "github.com/shapeshift/unchained-cosmos/service" log "github.com/sirupsen/logrus" diff --git a/docs/cosmos/docs.go b/docs/cosmos/docs.go new file mode 100644 index 0000000..32123d5 --- /dev/null +++ b/docs/cosmos/docs.go @@ -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 diff --git a/docs/cosmos/swagger.go b/docs/cosmos/swagger.go new file mode 100644 index 0000000..b6aaa07 --- /dev/null +++ b/docs/cosmos/swagger.go @@ -0,0 +1,67 @@ +package docs + +import ( + "github.com/shapeshift/unchained-cosmos/service" +) + +// swagger:route GET /account/{pubkey} account-tag accountEndpointId +// 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"` + } +} diff --git a/go.mod b/go.mod index 8e6a515..184e274 100644 --- a/go.mod +++ b/go.mod @@ -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 @@ -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 diff --git a/server/rest/rest.go b/server/rest/rest.go index 49be7ee..2ab4f3c 100644 --- a/server/rest/rest.go +++ b/server/rest/rest.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "github.com/gorilla/handlers" "github.com/gorilla/mux" "github.com/shapeshift/unchained-cosmos/service" @@ -44,6 +45,7 @@ func (s *UnchainedRestServer) start() { router.StrictSlash(true) router.HandleFunc("/account/{pubkey}", s.GetAccount) + router.HandleFunc("/account/{pubkey}/txs", s.GetTxHistory) listenAddr := s.config.RestListenAddr @@ -51,8 +53,11 @@ func (s *UnchainedRestServer) start() { 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))) } func writeError(writer http.ResponseWriter, errRes ErrorResponse) error { diff --git a/service/account.go b/service/account.go index f66495c..ebd3cd6 100644 --- a/service/account.go +++ b/service/account.go @@ -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 + 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) { diff --git a/service/txhistory.go b/service/txhistory.go index 6b79cb9..46e4490 100644 --- a/service/txhistory.go +++ b/service/txhistory.go @@ -61,6 +61,7 @@ type TxAction interface { GetType() string } type BaseTxAction struct { + // Example: transfer Type string `json:"type"` } @@ -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"` } diff --git a/service/types.go b/service/types.go index a290312..e5a7461 100644 --- a/service/types.go +++ b/service/types.go @@ -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"` } diff --git a/swagger.yaml b/swagger.yaml new file mode 100644 index 0000000..aa4e25c --- /dev/null +++ b/swagger.yaml @@ -0,0 +1,234 @@ +basePath: / +consumes: +- application/json +definitions: + Account: + properties: + accountNumber: + example: "9810" + format: uint64 + type: string + x-go-name: AccountNumber + balance: + example: "14250" + type: string + x-go-name: Balance + delegations: + items: + $ref: '#/definitions/Delegation' + type: array + x-go-name: Delegations + pubkey: + example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: Pubkey + sequence: + example: "43211" + format: uint64 + type: string + x-go-name: Sequence + tokens: + items: + $ref: '#/definitions/TokenAmount' + type: array + x-go-name: Tokens + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service + Delegation: + properties: + amount: + example: "45531" + type: string + x-go-name: Amount + shares: + example: "86544" + type: string + x-go-name: Shares + validator: + example: cosmosvaloper156gqf9837u7d4c4678yt3rl4ls9c5vuursrrzf + type: string + x-go-name: Validator + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service + HistTx: + description: Unchained API Historical Tx Model + properties: + actions: + items: + $ref: '#/definitions/TxAction' + type: array + x-go-name: Actions + blockHeight: + example: 34534 + format: int64 + type: integer + x-go-name: BlockHeight + confirmations: + example: 24346 + format: int64 + type: integer + x-go-name: Confirmations + fee: + example: "4223" + type: string + x-go-name: Fee + feeAsset: + example: '''uatom''' + type: string + x-go-name: FeeAsset + from: + example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: From + gasUsed: + example: "383312" + type: string + x-go-name: GasUsed + gasWanted: + example: "42345" + type: string + x-go-name: GasWanted + index: + example: 678678 + format: uint64 + type: integer + x-go-name: Index + memo: + example: This is a memo + type: string + x-go-name: Memo + status: + example: confirmed + type: string + x-go-name: Status + timestamp: + example: 1639598717717 + format: int64 + type: integer + x-go-name: Timestamp + to: + example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: To + txid: + example: B3127187CA99D7F2C0BAE4FA26512F204B6CEC80AD3C3AE514B8D3A77CD99B43 + type: string + x-go-name: TxID + type: + example: send + type: string + x-go-name: Type + value: + example: "866543" + type: string + x-go-name: Value + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service + TokenAmount: + description: Unchained API Types + properties: + amount: + example: "420" + type: string + x-go-name: Amount + denom: + example: uatom + type: string + x-go-name: Denom + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service + TxAction: + properties: + GetType: + type: string + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service + TxHistory: + properties: + pubkey: + description: TODO - pagination + example: cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: Pubkey + txs: + items: + $ref: '#/definitions/HistTx' + type: array + x-go-name: Txs + type: object + x-go-package: github.com/shapeshift/unchained-cosmos/service +host: localhost:1660 +info: + description: Documentation of our awesome API. + title: awesome. + version: 1.0.0 +paths: + /account/{pubkey}: + get: + description: Gets account information + operationId: accountEndpointId + parameters: + - description: Pubkey (address) to get account details for + in: path + name: pubkey + required: true + type: string + x-go-name: Pubkey + responses: + "200": + $ref: '#/responses/accountResponse' + "500": + $ref: '#/responses/accountResponseError' + tags: + - account-tag + /account/{pubkey}/txs: + get: + description: Handles getting TX History for an account by pubkey (address) + operationId: txsEndpointId + parameters: + - description: Pubkey (address) to get tx history for + in: path + name: pubkey + required: true + type: string + x-go-name: Pubkey + responses: + "200": + $ref: '#/responses/txsResponse' + "500": + $ref: '#/responses/txsResponseError' + tags: + - txs-tag +produces: +- application/json +responses: + accountResponse: + description: Account response contains informations about account (balance, sequence, + etc) + schema: + $ref: '#/definitions/Account' + accountResponseError: + description: Account response error + schema: + properties: + error: + example: error reading account for cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: Error + type: object + txsResponse: + description: Tsxxs response contains tx history + schema: + $ref: '#/definitions/TxHistory' + txsResponseError: + description: Txs response error + schema: + properties: + error: + example: error reading txhistory for recipient cosmos1fx4jwv3aalxqwmrpymn34l582lnehr3eqwuz9e + type: string + x-go-name: Error + type: object +schemes: +- http +swagger: "2.0"