-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add /blocks , /blocks/{hashOrHeight} APIs (#732)
* Add /blocks , /blocks/{hashOrHeight} api handlers - Add storage.WalkBlocks func for handlers - Add resource.Block * Block cursor as height * Add SkipCursor for supporting cursor as height * Add blocks handler tests * Add api doc for blocks api * Default cursor is common.GenesisBlockHeight * Fix bug about SkipCursor * Fix test for walk * Typo
- Loading branch information
Showing
18 changed files
with
481 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# Group Blocks | ||
Blocks API | ||
|
||
## Blocks [/api/v1/blocks?cursor={cursor}&limit={limit}&reverse={reverse}] | ||
|
||
+ Parameters | ||
+ cursor: `1207` (string, optional) - a block height as cursor | ||
+ reverse: `false` (string, optional) | ||
+ limit: `100` (integer, optional) | ||
|
||
### Retrieve blocks [GET] | ||
|
||
<p>Retrieve all valid blocks </p> | ||
|
||
<p> Streaming mode supported with header "Accept": "text/event-stream" </p> | ||
|
||
+ Response 200 (application/hal+json; charset=utf-8) | ||
+ Attributes (Blocks) | ||
|
||
+ Response 500 (application/problem+json; charset=utf-8) | ||
+ Attributes (Problem) | ||
|
||
|
||
## Block Details [/api/v1/blocks/{hashOrHeight}] | ||
|
||
+ Parameters | ||
+ hashOrHeight: `CLNes5kkg7ozgnHBhpBXHMHFtPKo7z4RF8NZpNGRUB4i` `1207` (string,required) - a block hash or height | ||
|
||
### Retrieve a block [GET] | ||
|
||
<p> Retrieve a block by the hash or height <p> | ||
|
||
+ Response 200 (application/hal+json; charset=utf-8) | ||
+ Attributes (Block) | ||
+ Response 404 (application/problem+json; charset=utf-8) | ||
+ Attributes (Problem NotFound) | ||
+ Response 500 (application/problem+json; charset=utf-8) | ||
+ Attributes (Problem) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package api | ||
|
||
import ( | ||
"net/http" | ||
"strconv" | ||
|
||
"boscoin.io/sebak/lib/block" | ||
"boscoin.io/sebak/lib/errors" | ||
"boscoin.io/sebak/lib/network/httputils" | ||
"boscoin.io/sebak/lib/node/runner/api/resource" | ||
|
||
"github.com/gorilla/mux" | ||
) | ||
|
||
func (api NetworkHandlerAPI) GetBlockHandler(w http.ResponseWriter, r *http.Request) { | ||
vars := mux.Vars(r) | ||
hash := vars["hashOrHeight"] | ||
if hash == "" { | ||
err := errors.BadRequestParameter | ||
httputils.WriteJSONError(w, err) | ||
return | ||
} | ||
|
||
var isHash bool | ||
height, err := strconv.ParseUint(hash, 10, 64) | ||
if err != nil { | ||
isHash = true | ||
} | ||
|
||
var res resource.Resource | ||
{ | ||
var b block.Block | ||
var err error | ||
if isHash { | ||
b, err = block.GetBlock(api.storage, hash) | ||
} else { | ||
b, err = block.GetBlockByHeight(api.storage, height) | ||
} | ||
|
||
if err != nil { | ||
httputils.WriteJSONError(w, err) | ||
return | ||
} | ||
res = resource.NewBlock(&b) | ||
} | ||
httputils.MustWriteJSON(w, 200, res) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package api | ||
|
||
import ( | ||
"bufio" | ||
"encoding/json" | ||
"io/ioutil" | ||
"strings" | ||
"testing" | ||
|
||
"boscoin.io/sebak/lib/block" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestBlockHandler(t *testing.T) { | ||
ts, st := prepareAPIServer() | ||
defer st.Close() | ||
defer ts.Close() | ||
|
||
genesis := block.GetLatestBlock(st) | ||
|
||
reqFunc := func(url string) map[string]interface{} { | ||
|
||
respBody := request(ts, url, false) | ||
defer respBody.Close() | ||
bs, err := ioutil.ReadAll(bufio.NewReader(respBody)) | ||
require.NoError(t, err) | ||
|
||
result := make(map[string]interface{}) | ||
err = json.Unmarshal(bs, &result) | ||
require.NoError(t, err) | ||
|
||
return result | ||
} | ||
|
||
{ | ||
url := strings.Replace(GetBlockHandlerPattern, "{hashOrHeight}", "1", 1) | ||
res := reqFunc(url) | ||
require.Equal(t, res["hash"], genesis.Hash) | ||
require.Equal(t, res["transactions_root"], genesis.TransactionsRoot) | ||
} | ||
|
||
{ | ||
url := strings.Replace(GetBlockHandlerPattern, "{hashOrHeight}", genesis.Hash, 1) | ||
res := reqFunc(url) | ||
require.Equal(t, res["hash"], genesis.Hash) | ||
require.Equal(t, res["transactions_root"], genesis.TransactionsRoot) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package api | ||
|
||
import ( | ||
"net/http" | ||
"strconv" | ||
|
||
"boscoin.io/sebak/lib/block" | ||
"boscoin.io/sebak/lib/common" | ||
"boscoin.io/sebak/lib/common/observer" | ||
"boscoin.io/sebak/lib/network/httputils" | ||
"boscoin.io/sebak/lib/node/runner/api/resource" | ||
"boscoin.io/sebak/lib/storage" | ||
) | ||
|
||
func (api NetworkHandlerAPI) GetBlocksHandler(w http.ResponseWriter, r *http.Request) { | ||
p, err := NewPageQuery(r) | ||
if err != nil { | ||
httputils.WriteJSONError(w, err) | ||
return | ||
} | ||
|
||
var ( | ||
cursor []byte // cursor as height | ||
blocks []resource.Resource | ||
) | ||
|
||
var option *storage.WalkOption | ||
{ | ||
height, err := strconv.ParseUint(string(p.Cursor()), 10, 64) | ||
if err != nil { | ||
height = common.GenesisBlockHeight // default cursor is genesis block height | ||
} | ||
option = storage.NewWalkOption(block.GetBlockKeyPrefixHeight(height), p.Limit(), p.Reverse(), false) | ||
if httputils.IsEventStream(r) { | ||
option.Limit = 10 | ||
} | ||
} | ||
|
||
{ | ||
err := block.WalkBlocks(api.storage, option, func(b *block.Block, key []byte) (next bool, err error) { | ||
blocks = append(blocks, resource.NewBlock(b)) | ||
height := b.Height | ||
if height > 1 { | ||
if option.Reverse { | ||
height-- | ||
} else { | ||
height++ | ||
} | ||
} | ||
cursor = []byte(strconv.FormatUint(height, 10)) | ||
return true, nil | ||
}) | ||
if err != nil { | ||
httputils.WriteJSONError(w, err) | ||
return | ||
|
||
} | ||
} | ||
|
||
if httputils.IsEventStream(r) { | ||
es := NewEventStream(w, r, renderEventStream, DefaultContentType) | ||
for _, b := range blocks { | ||
es.Render(b) | ||
} | ||
es.Run(observer.BlockObserver, block.EventBlockPrefix) | ||
return | ||
} | ||
|
||
list := p.ResourceList(blocks, cursor) | ||
httputils.MustWriteJSON(w, 200, list) | ||
} |
Oops, something went wrong.