mirror of
https://github.com/bigchaindb/bigchaindb.git
synced 2024-10-13 13:34:05 +00:00
Merge pull request #1026 from bigchaindb/feat/api/statuses
implement statuses endpoint
This commit is contained in:
commit
03d46b40f9
@ -1,6 +1,11 @@
|
||||
""" API routes definition """
|
||||
from flask_restful import Api
|
||||
from bigchaindb.web.views import info, transactions as tx, unspents
|
||||
from bigchaindb.web.views import (
|
||||
info,
|
||||
statuses,
|
||||
transactions as tx,
|
||||
unspents,
|
||||
)
|
||||
|
||||
|
||||
def add_routes(app):
|
||||
@ -17,8 +22,8 @@ def r(*args, **kwargs):
|
||||
|
||||
|
||||
ROUTES_API_V1 = [
|
||||
r('statuses/', statuses.StatusApi),
|
||||
r('transactions/<string:tx_id>', tx.TransactionApi),
|
||||
r('transactions/<string:tx_id>/status', tx.TransactionStatusApi),
|
||||
r('transactions', tx.TransactionListApi),
|
||||
r('unspents/', unspents.UnspentListApi),
|
||||
]
|
||||
|
62
bigchaindb/web/views/statuses.py
Normal file
62
bigchaindb/web/views/statuses.py
Normal file
@ -0,0 +1,62 @@
|
||||
"""This module provides the blueprint for the statuses API endpoints.
|
||||
|
||||
For more information please refer to the documentation on ReadTheDocs:
|
||||
- https://docs.bigchaindb.com/projects/server/en/latest/drivers-clients/
|
||||
http-client-server-api.html
|
||||
"""
|
||||
from flask import current_app
|
||||
from flask_restful import Resource, reqparse
|
||||
|
||||
from bigchaindb.web.views.base import make_error
|
||||
|
||||
|
||||
class StatusApi(Resource):
|
||||
def get(self):
|
||||
"""API endpoint to get details about the status of a transaction or a block.
|
||||
|
||||
Return:
|
||||
A ``dict`` in the format ``{'status': <status>}``, where
|
||||
``<status>`` is one of "valid", "invalid", "undecided", "backlog".
|
||||
"""
|
||||
parser = reqparse.RequestParser()
|
||||
parser.add_argument('tx_id', type=str)
|
||||
parser.add_argument('block_id', type=str)
|
||||
|
||||
args = parser.parse_args(strict=True)
|
||||
tx_id = args['tx_id']
|
||||
block_id = args['block_id']
|
||||
|
||||
# logical xor - exactly one query argument required
|
||||
if bool(tx_id) == bool(block_id):
|
||||
return make_error(400, "Provide exactly one query parameter. Choices are: block_id, tx_id")
|
||||
|
||||
pool = current_app.config['bigchain_pool']
|
||||
status, links = None, None
|
||||
|
||||
with pool() as bigchain:
|
||||
if tx_id:
|
||||
status = bigchain.get_status(tx_id)
|
||||
links = {
|
||||
"tx": "/transactions/{}".format(tx_id)
|
||||
}
|
||||
|
||||
elif block_id:
|
||||
_, status = bigchain.get_block(block_id=block_id, include_status=True)
|
||||
# TODO: enable once blocks endpoint is available
|
||||
# links = {
|
||||
# "block": "/blocks/{}".format(args['block_id'])
|
||||
# }
|
||||
|
||||
if not status:
|
||||
return make_error(404)
|
||||
|
||||
response = {
|
||||
'status': status
|
||||
}
|
||||
|
||||
if links:
|
||||
response.update({
|
||||
"_links": links
|
||||
})
|
||||
|
||||
return response
|
@ -46,29 +46,6 @@ class TransactionApi(Resource):
|
||||
return tx.to_dict()
|
||||
|
||||
|
||||
class TransactionStatusApi(Resource):
|
||||
def get(self, tx_id):
|
||||
"""API endpoint to get details about the status of a transaction.
|
||||
|
||||
Args:
|
||||
tx_id (str): the id of the transaction.
|
||||
|
||||
Return:
|
||||
A ``dict`` in the format ``{'status': <status>}``, where
|
||||
``<status>`` is one of "valid", "invalid", "undecided", "backlog".
|
||||
"""
|
||||
|
||||
pool = current_app.config['bigchain_pool']
|
||||
|
||||
with pool() as bigchain:
|
||||
status = bigchain.get_status(tx_id)
|
||||
|
||||
if not status:
|
||||
return make_error(404)
|
||||
|
||||
return {'status': status}
|
||||
|
||||
|
||||
class TransactionListApi(Resource):
|
||||
def post(self):
|
||||
"""API endpoint to push transactions to the Federation.
|
||||
|
98
tests/web/test_statuses.py
Normal file
98
tests/web/test_statuses.py
Normal file
@ -0,0 +1,98 @@
|
||||
import pytest
|
||||
|
||||
from bigchaindb.models import Transaction
|
||||
|
||||
STATUSES_ENDPOINT = '/api/v1/statuses'
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_transaction_status_endpoint(b, client, user_pk):
|
||||
input_tx = b.get_owned_ids(user_pk).pop()
|
||||
tx, status = b.get_transaction(input_tx.txid, include_status=True)
|
||||
res = client.get(STATUSES_ENDPOINT + "?tx_id=" + input_tx.txid)
|
||||
assert status == res.json['status']
|
||||
assert res.json['_links']['tx'] == "/transactions/{}".format(input_tx.txid)
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_transaction_status_endpoint_returns_404_if_not_found(client):
|
||||
res = client.get(STATUSES_ENDPOINT + "?tx_id=123")
|
||||
assert res.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_block_status_endpoint_undecided(b, client):
|
||||
tx = Transaction.create([b.me], [([b.me], 1)])
|
||||
tx = tx.sign([b.me_private])
|
||||
|
||||
block = b.create_block([tx])
|
||||
b.write_block(block)
|
||||
|
||||
status = b.block_election_status(block.id, block.voters)
|
||||
|
||||
res = client.get(STATUSES_ENDPOINT + "?block_id=" + block.id)
|
||||
assert status == res.json['status']
|
||||
assert '_links' not in res.json
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_block_status_endpoint_valid(b, client):
|
||||
tx = Transaction.create([b.me], [([b.me], 1)])
|
||||
tx = tx.sign([b.me_private])
|
||||
|
||||
block = b.create_block([tx])
|
||||
b.write_block(block)
|
||||
|
||||
# vote the block valid
|
||||
vote = b.vote(block.id, b.get_last_voted_block().id, True)
|
||||
b.write_vote(vote)
|
||||
|
||||
status = b.block_election_status(block.id, block.voters)
|
||||
|
||||
res = client.get(STATUSES_ENDPOINT + "?block_id=" + block.id)
|
||||
assert status == res.json['status']
|
||||
assert '_links' not in res.json
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_block_status_endpoint_invalid(b, client):
|
||||
tx = Transaction.create([b.me], [([b.me], 1)])
|
||||
tx = tx.sign([b.me_private])
|
||||
|
||||
block = b.create_block([tx])
|
||||
b.write_block(block)
|
||||
|
||||
# vote the block valid
|
||||
vote = b.vote(block.id, b.get_last_voted_block().id, False)
|
||||
b.write_vote(vote)
|
||||
|
||||
status = b.block_election_status(block.id, block.voters)
|
||||
|
||||
res = client.get(STATUSES_ENDPOINT + "?block_id=" + block.id)
|
||||
assert status == res.json['status']
|
||||
assert '_links' not in res.json
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_block_status_endpoint_returns_404_if_not_found(client):
|
||||
res = client.get(STATUSES_ENDPOINT + "?block_id=123")
|
||||
assert res.status_code == 404
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
def test_get_status_endpoint_returns_400_bad_query_params(client):
|
||||
res = client.get(STATUSES_ENDPOINT)
|
||||
assert res.status_code == 400
|
||||
|
||||
res = client.get(STATUSES_ENDPOINT + "?ts_id=123")
|
||||
assert res.status_code == 400
|
||||
|
||||
res = client.get(STATUSES_ENDPOINT + "?tx_id=123&block_id=123")
|
||||
assert res.status_code == 400
|
@ -158,27 +158,3 @@ def test_post_invalid_transfer_transaction_returns_400(b, client, user_pk, user_
|
||||
|
||||
res = client.post(TX_ENDPOINT, data=json.dumps(transfer_tx.to_dict()))
|
||||
assert res.status_code == 400
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_transaction_status_endpoint(b, client, user_pk):
|
||||
input_tx = b.get_owned_ids(user_pk).pop()
|
||||
tx, status = b.get_transaction(input_tx.txid, include_status=True)
|
||||
res = client.get(TX_ENDPOINT + input_tx.txid + "/status")
|
||||
assert status == res.json['status']
|
||||
assert res.status_code == 200
|
||||
|
||||
res = client.get(TX_ENDPOINT + input_tx.txid + "/status/")
|
||||
assert status == res.json['status']
|
||||
assert res.status_code == 200
|
||||
|
||||
|
||||
@pytest.mark.bdb
|
||||
@pytest.mark.usefixtures('inputs')
|
||||
def test_get_transaction_status_returns_404_if_not_found(client):
|
||||
res = client.get(TX_ENDPOINT + '123' + "/status")
|
||||
assert res.status_code == 404
|
||||
|
||||
res = client.get(TX_ENDPOINT + '123' + "/status/")
|
||||
assert res.status_code == 404
|
||||
|
Loading…
x
Reference in New Issue
Block a user