diff --git a/docs/server/generate_http_server_api_documentation.py b/docs/server/generate_http_server_api_documentation.py index 7c7c4b97..c36b10b5 100644 --- a/docs/server/generate_http_server_api_documentation.py +++ b/docs/server/generate_http_server_api_documentation.py @@ -4,13 +4,61 @@ import json import os import os.path -from bigchaindb.common.transaction import Transaction +from bigchaindb.common.transaction import Transaction, Input, TransactionLink +from bigchaindb.core import Bigchain +from bigchaindb.models import Block +from bigchaindb.web import server TPLS = {} + +TPLS['index-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +%(index)s +""" + +TPLS['api-index-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +%(api_index)s +""" + +TPLS['get-tx-id-request'] = """\ +GET /api/v1/transactions/%(txid)s HTTP/1.1 +Host: example.com + +""" + + +TPLS['get-tx-id-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +%(tx)s +""" + + +TPLS['get-tx-by-asset-request'] = """\ +GET /api/v1/transactions?operation=TRANSFER&asset_id=%(txid)s HTTP/1.1 +Host: example.com + +""" + + +TPLS['get-tx-by-asset-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +[%(tx_transfer)s, +%(tx_transfer_last)s] +""" + TPLS['post-tx-request'] = """\ -POST /transactions/ HTTP/1.1 +POST /api/v1/transactions/ HTTP/1.1 Host: example.com Content-Type: application/json @@ -19,62 +67,214 @@ Content-Type: application/json TPLS['post-tx-response'] = """\ -HTTP/1.1 201 Created +HTTP/1.1 202 Accepted Content-Type: application/json %(tx)s """ -TPLS['get-tx-status-request'] = """\ -GET /transactions/%(txid)s/status HTTP/1.1 +TPLS['get-statuses-tx-request'] = """\ +GET /statuses?tx_id=%(txid)s HTTP/1.1 Host: example.com """ -TPLS['get-tx-status-response'] = """\ +TPLS['get-statuses-tx-invalid-response'] = """\ HTTP/1.1 200 OK Content-Type: application/json { - "status": "valid" + "status": "invalid" } """ -TPLS['get-tx-request'] = """\ -GET /transactions/%(txid)s HTTP/1.1 +TPLS['get-statuses-tx-valid-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "status": "valid", + "_links": { + "tx": "/transactions/%(txid)s" + } +} +""" + + +TPLS['get-statuses-block-request'] = """\ +GET /api/v1/statuses?block_id=%(blockid)s HTTP/1.1 Host: example.com """ -TPLS['get-tx-response'] = """\ +TPLS['get-statuses-block-invalid-response'] = """\ HTTP/1.1 200 OK Content-Type: application/json -%(tx)s +{ + "status": "invalid" +} +""" + + +TPLS['get-statuses-block-valid-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "status": "valid", + "_links": { + "block": "/blocks/%(blockid)s" + } +} +""" + + +TPLS['get-block-request'] = """\ +GET /api/v1/blocks/%(blockid)s HTTP/1.1 +Host: example.com + +""" + + +TPLS['get-block-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +%(block)s +""" + + +TPLS['get-block-txid-request'] = """\ +GET /api/v1/blocks?tx_id=%(txid)s HTTP/1.1 +Host: example.com + +""" + + +TPLS['get-block-txid-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +%(block_list)s +""" + + +TPLS['get-vote-request'] = """\ +GET /api/v1/votes?block_id=%(blockid)s HTTP/1.1 +Host: example.com + +""" + + +TPLS['get-vote-response'] = """\ +HTTP/1.1 200 OK +Content-Type: application/json + +[%(vote)s] """ def main(): """ Main function """ + + ctx = {} + + def pretty_json(data): + return json.dumps(data, indent=2, sort_keys=True) + + client = server.create_app().test_client() + + host = 'example.com:9984' + + # HTTP Index + res = client.get('/', environ_overrides={'HTTP_HOST': host}) + res_data = json.loads(res.data.decode()) + res_data['keyring'] = [ + "6qHyZew94NMmUTYyHnkZsB8cxJYuRNEiEpXHe1ih9QX3", + "AdDuyrTyjrDt935YnFu4VBCVDhHtY2Y6rcy7x2TFeiRi" + ] + ctx['index'] = pretty_json(res_data) + + # API index + res = client.get('/api/v1/', environ_overrides={'HTTP_HOST': host}) + ctx['api_index'] = pretty_json(json.loads(res.data.decode())) + + # tx create privkey = 'CfdqtD7sS7FgkMoGPXw55MVGGFwQLAoHYTcBhZDtF99Z' pubkey = '4K9sWUMFwTgaDGPfdynrbxWqWS6sWmKbZoTjxLtVUibD' - tx = Transaction.create([pubkey], [([pubkey], 1)]) + asset = {'msg': 'Hello BigchainDB!'} + tx = Transaction.create([pubkey], [([pubkey], 1)], asset=asset, metadata={'sequence': 0}) tx = tx.sign([privkey]) - tx_json = json.dumps(tx.to_dict(), indent=2, sort_keys=True) + ctx['tx'] = pretty_json(tx.to_dict()) + ctx['public_keys'] = tx.outputs[0].public_keys[0] + ctx['txid'] = tx.id + + # tx transfer + privkey_transfer = '3AeWpPdhEZzWLYfkfYHBfMFC2r1f8HEaGS9NtbbKssya' + pubkey_transfer = '3yfQPHeWAa1MxTX9Zf9176QqcpcnWcanVZZbaHb8B3h9' + + cid = 0 + input_ = Input(fulfillment=tx.outputs[cid].fulfillment, + fulfills=TransactionLink(txid=tx.id, output=cid), + owners_before=tx.outputs[cid].public_keys) + tx_transfer = Transaction.transfer([input_], [([pubkey_transfer], 1)], asset_id=tx.id, metadata={'sequence': 1}) + tx_transfer = tx_transfer.sign([privkey]) + ctx['tx_transfer'] = pretty_json(tx_transfer.to_dict()) + ctx['public_keys_transfer'] = tx_transfer.outputs[0].public_keys[0] + ctx['tx_transfer_id'] = tx_transfer.id + + # privkey_transfer_last = 'sG3jWDtdTXUidBJK53ucSTrosktG616U3tQHBk81eQe' + pubkey_transfer_last = '3Af3fhhjU6d9WecEM9Uw5hfom9kNEwE7YuDWdqAUssqm' + + cid = 0 + input_ = Input(fulfillment=tx_transfer.outputs[cid].fulfillment, + fulfills=TransactionLink(txid=tx_transfer.id, output=cid), + owners_before=tx_transfer.outputs[cid].public_keys) + tx_transfer_last = Transaction.transfer([input_], [([pubkey_transfer_last], 1)], + asset_id=tx.id, metadata={'sequence': 2}) + tx_transfer_last = tx_transfer_last.sign([privkey_transfer]) + ctx['tx_transfer_last'] = pretty_json(tx_transfer_last.to_dict()) + ctx['tx_transfer_last_id'] = tx_transfer_last.id + ctx['public_keys_transfer_last'] = tx_transfer_last.outputs[0].public_keys[0] + + # block + node_private = "5G2kE1zJAgTajkVSbPAQWo4c2izvtwqaNHYsaNpbbvxX" + node_public = "DngBurxfeNVKZWCEcDnLj1eMPAS7focUZTE5FndFGuHT" + signature = "53wxrEQDYk1dXzmvNSytbCfmNVnPqPkDQaTnAe8Jf43s6ssejPxezkCvUnGTnduNUmaLjhaan1iRLi3peu6s5DzA" + block = Block(transactions=[tx], node_pubkey=node_public, voters=[node_public], signature=signature) + ctx['block'] = pretty_json(block.to_dict()) + ctx['blockid'] = block.id + + block_transfer = Block(transactions=[tx_transfer], node_pubkey=node_public, + voters=[node_public], signature=signature) + ctx['block_transfer'] = pretty_json(block.to_dict()) + + # vote + DUMMY_SHA3 = '0123456789abcdef' * 4 + b = Bigchain(public_key=node_public, private_key=node_private) + vote = b.vote(block.id, DUMMY_SHA3, True) + ctx['vote'] = pretty_json(vote) + + # block status + block_list = [ + block_transfer.id, + block.id + ] + ctx['block_list'] = pretty_json(block_list) base_path = os.path.join(os.path.dirname(__file__), 'source/drivers-clients/samples') - if not os.path.exists(base_path): os.makedirs(base_path) for name, tpl in TPLS.items(): path = os.path.join(base_path, name + '.http') - code = tpl % {'tx': tx_json, 'txid': tx.id} + code = tpl % ctx with open(path, 'w') as handle: handle.write(code) diff --git a/docs/server/source/drivers-clients/http-client-server-api.rst b/docs/server/source/drivers-clients/http-client-server-api.rst index 969d912b..9e66f603 100644 --- a/docs/server/source/drivers-clients/http-client-server-api.rst +++ b/docs/server/source/drivers-clients/http-client-server-api.rst @@ -1,58 +1,136 @@ The HTTP Client-Server API ========================== -.. note:: - - The HTTP client-server API is currently quite rudimentary. For example, - there is no ability to do complex queries using the HTTP API. We plan to add - more querying capabilities in the future. - This page assumes you already know an API Root URL for a BigchainDB node or reverse proxy. -It should be something like ``http://apihosting4u.net:9984`` -or ``http://12.34.56.78:9984``. +It should be something like ``https://example.com:9984`` +or ``https://12.34.56.78:9984``. If you set up a BigchainDB node or reverse proxy yourself, and you're not sure what the API Root URL is, then see the last section of this page for help. -API Root URL ------------- - -If you send an HTTP GET request to the API Root URL -e.g. ``http://localhost:9984`` -or ``http://apihosting4u.net:9984`` -(with no ``/api/v1/`` on the end), -then you should get an HTTP response -with something like the following in the body: - -.. code-block:: json - - { - "keyring": [ - "6qHyZew94NMmUTYyHnkZsB8cxJYuRNEiEpXHe1ih9QX3", - "AdDuyrTyjrDt935YnFu4VBCVDhHtY2Y6rcy7x2TFeiRi" - ], - "public_key": "AiygKSRhZWTxxYT4AfgKoTG4TZAoPsWoEt6C6bLq4jJR", - "software": "BigchainDB", - "version": "0.6.0" - } - - -POST /transactions/ +BigchainDB Root URL ------------------- -.. http:post:: /transactions/ +If you send an HTTP GET request to the BigchainDB Root URL +e.g. ``http://localhost:9984`` +or ``https://example.com:9984`` +(with no ``/api/v1/`` on the end), +then you should get an HTTP response +with something like the following in the body: + +.. literalinclude:: samples/index-response.http + :language: http + + +API Root Endpoint +------------------- + +If you send an HTTP GET request to the API Root Endpoint +e.g. ``http://localhost:9984/api/v1/`` +or ``https://example.com:9984/api/v1/``, +then you should get an HTTP response +that allows you to discover the BigchainDB API endpoints: + +.. literalinclude:: samples/api-index-response.http + :language: http + + +Transactions +------------------- + +.. http:get:: /api/v1/transactions/{tx_id} + + Get the transaction with the ID ``tx_id``. + + This endpoint returns a transaction only if a ``VALID`` block on + ``bigchain`` exists. + + :param tx_id: transaction ID + :type tx_id: hex string + + **Example request**: + + .. literalinclude:: samples/get-tx-id-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-tx-id-response.http + :language: http + + :resheader Content-Type: ``application/json`` + + :statuscode 200: A transaction with that ID was found. + :statuscode 404: A transaction with that ID was not found. + +.. http:get:: /api/v1/transactions + + The unfiltered ``/api/v1/transactions`` endpoint without any query parameters + returns a status code `400`. For valid filters, see the sections below. + + There are however filtered requests that might come of use, given the endpoint is + queried correctly. Some of them include retrieving a list of transactions + that include: + + * `Transactions related to a specific asset <#get--transactions?asset_id=asset_id&operation=CREATE|TRANSFER>`_ + + In this section, we've listed those particular requests, as they will likely + to be very handy when implementing your application on top of BigchainDB. + + .. note:: + Looking up transactions with a specific ``metadata`` field is currently not supported, + however, providing a way to query based on ``metadata`` data is on our roadmap. + + A generalization of those parameters follows: + + :query string asset_id: The ID of the asset. + + :query string operation: (Optional) One of the two supported operations of a transaction: ``CREATE``, ``TRANSFER``. + +.. http:get:: /api/v1/transactions?asset_id={asset_id}&operation={CREATE|TRANSFER} + + Get a list of transactions that use an asset with the ID ``asset_id``. + Every ``TRANSFER`` transaction that originates from a ``CREATE`` transaction + with ``asset_id`` will be included. This allows users to query the entire history or + provenance of an asset. + + This endpoint returns transactions only if they are decided ``VALID`` by the server. + + :query string operation: (Optional) One of the two supported operations of a transaction: ``CREATE``, ``TRANSFER``. + + :query string asset_id: asset ID. + + **Example request**: + + .. literalinclude:: samples/get-tx-by-asset-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-tx-by-asset-response.http + :language: http + + :resheader Content-Type: ``application/json`` + + :statuscode 200: A list of transactions containing an asset with ID ``asset_id`` was found and returned. + :statuscode 400: The request wasn't understood by the server, e.g. the ``asset_id`` querystring was not included in the request. + + +.. http:post:: /api/v1/transactions Push a new transaction. - Note: The posted transaction should be a valid and signed :doc:`transaction <../data-models/transaction-model>`. - The steps to build a valid transaction are beyond the scope of this page. - One would normally use a driver such as the `BigchainDB Python Driver - `_ to - build a valid transaction. The exact contents of a valid transaction depend - on the associated public/private keypairs. + .. note:: + The posted `transaction + `_ + should be structurally valid and not spending an already spent output. + The steps to build a valid transaction are beyond the scope of this page. + One would normally use a driver such as the `BigchainDB Python Driver + `_ + to build a valid transaction. **Example request**: @@ -64,110 +142,255 @@ POST /transactions/ .. literalinclude:: samples/post-tx-response.http :language: http - :statuscode 201: A new transaction was created. - :statuscode 400: The transaction was invalid and not created. + :resheader Content-Type: ``application/json`` + + :statuscode 202: The pushed transaction was accepted in the ``BACKLOG``, but the processing has not been completed. + :statuscode 400: The transaction was malformed and not accepted in the ``BACKLOG``. -GET /transactions/{tx_id}/status --------------------------------- +Transaction Outputs +------------------- -.. http:get:: /transactions/{tx_id}/status - - Get the status of the transaction with the ID ``tx_id``, if a transaction - with that ``tx_id`` exists. - - The possible status values are ``backlog``, ``undecided``, ``valid`` or - ``invalid``. - - :param tx_id: transaction ID - :type tx_id: hex string - - **Example request**: - - .. literalinclude:: samples/get-tx-status-request.http - :language: http - - **Example response**: - - .. literalinclude:: samples/get-tx-status-response.http - :language: http - - :statuscode 200: A transaction with that ID was found and the status is returned. - :statuscode 404: A transaction with that ID was not found. +The ``/api/v1/outputs`` endpoint returns transactions outputs filtered by a +given public key, and optionally filtered to only include outputs that have +not already been spent. -GET /transactions/{tx_id} -------------------------- +.. http:get:: /api/v1/outputs?public_key={public_key} -.. http:get:: /transactions/{tx_id} + Get transaction outputs by public key. The `public_key` parameter must be + a base58 encoded ed25519 public key associated with transaction output + ownership. - Get the transaction with the ID ``tx_id``. + Returns a list of links to transaction outputs. - This endpoint returns only a transaction from a ``VALID`` or ``UNDECIDED`` - block on ``bigchain``, if exists. + :param public_key: Base58 encoded public key associated with output ownership. This parameter is mandatory and without it the endpoint will return a ``400`` response code. + :param unspent: Boolean value ("true" or "false") indicating if the result set should be limited to outputs that are available to spend. - :param tx_id: transaction ID - :type tx_id: hex string - - **Example request**: - - .. literalinclude:: samples/get-tx-request.http - :language: http - - **Example response**: - - .. literalinclude:: samples/get-tx-response.http - :language: http - - :statuscode 200: A transaction with that ID was found. - :statuscode 404: A transaction with that ID was not found. - - -GET /unspents/ -------------------------- - -.. note:: - - This endpoint (unspents) is not yet implemented. We published it here for preview and comment. - - -.. http:get:: /unspents?owner_after={owner_after} - - Get a list of links to transactions' outputs that have not been used in - a previous transaction and could hence be called unspent outputs - (or simply: unspents). - - This endpoint will return a ``HTTP 400 Bad Request`` if the querystring - ``owner_after`` happens to not be defined in the request. - - Note that if unspents for a certain ``public_key`` have not been found by - the server, this will result in the server returning a 200 OK HTTP status - code and an empty list in the response's body. - - :param owner_after: A public key, able to validly spend an output of a transaction, assuming the user also has the corresponding private key. - :type owner_after: base58 encoded string **Example request**: .. sourcecode:: http - GET /unspents?owner_after=1AAAbbb...ccc HTTP/1.1 + GET /api/v1/outputs?public_key=1AAAbbb...ccc HTTP/1.1 + Host: example.com + + **Example response**: + + .. sourcecode:: http + + HTTP/1.1 200 OK + Content-Type: application/json + + [ + "../transactions/2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e/outputs/0", + "../transactions/2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e/outputs/1" + ] + + :statuscode 200: A list of outputs were found and returned in the body of the response. + :statuscode 400: The request wasn't understood by the server, e.g. the ``public_key`` querystring was not included in the request. + + +Statuses +-------------------------------- + +.. http:get:: /api/v1/statuses + + Get the status of an asynchronously written transaction or block by their id. + + A link to the resource is also provided in the returned payload under + ``_links``. + + :query string tx_id: transaction ID + :query string block_id: block ID + + .. note:: + + Exactly one of the ``tx_id`` or ``block_id`` query parameters must be + used together with this endpoint (see below for getting `transaction + statuses <#get--statuses?tx_id=tx_id>`_ and `block statuses + <#get--statuses?block_id=block_id>`_). + + +.. http:get:: /api/v1/statuses?tx_id={tx_id} + + Get the status of a transaction. + + The possible status values are ``undecided``, ``valid`` or ``backlog``. + If a transaction in neither of those states is found, a ``404 Not Found`` + HTTP status code is returned. `We're currently looking into ways to unambigously let the user know about a transaction's status that was included in an invalid block. `_ + + **Example request**: + + .. literalinclude:: samples/get-statuses-tx-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-statuses-tx-valid-response.http + :language: http + + :resheader Content-Type: ``application/json`` + :resheader Location: Once the transaction has been persisted, this header will link to the actual resource. + + :statuscode 200: A transaction with that ID was found. + :statuscode 404: A transaction with that ID was not found. + + +.. http:get:: /api/v1/statuses?block_id={block_id} + + Get the status of a block. + + The possible status values are ``undecided``, ``valid`` or ``invalid``. + + **Example request**: + + .. literalinclude:: samples/get-statuses-block-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-statuses-block-invalid-response.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-statuses-block-valid-response.http + :language: http + + :resheader Content-Type: ``application/json`` + :resheader Location: Once the block has been persisted, this header will link to the actual resource. + + :statuscode 200: A block with that ID was found. + :statuscode 404: A block with that ID was not found. + + +Advanced Usage +-------------------------------- + +The following endpoints are more advanced and meant for debugging and transparency purposes. + +More precisely, the `blocks endpoint <#blocks>`_ allows you to retrieve a block by ``block_id`` as well the list of blocks that +a certain transaction with ``tx_id`` occured in (a transaction can occur in multiple ``invalid`` blocks until it +either gets rejected or validated by the system). This endpoint gives the ability to drill down on the lifecycle of a +transaction + +The `votes endpoint <#votes>`_ contains all the voting information for a specific block. So after retrieving the +``block_id`` for a given ``tx_id``, one can now simply inspect the votes that happened at a specific time on that block. + + +Blocks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. http:get:: /api/v1/blocks/{block_id} + + Get the block with the ID ``block_id``. Any blocks, be they ``VALID``, ``UNDECIDED`` or ``INVALID`` will be + returned. To check a block's status independently, use the `Statuses endpoint <#status>`_. + To check the votes on a block, have a look at the `votes endpoint <#votes>`_. + + :param block_id: block ID + :type block_id: hex string + + **Example request**: + + .. literalinclude:: samples/get-block-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-block-response.http + :language: http + + + :resheader Content-Type: ``application/json`` + + :statuscode 200: A block with that ID was found. + :statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks`` without the ``block_id``. + :statuscode 404: A block with that ID was not found. + + +.. http:get:: /api/v1/blocks + + The unfiltered ``/blocks`` endpoint without any query parameters returns a `400` status code. + The list endpoint should be filtered with a ``tx_id`` query parameter, + see the ``/blocks?tx_id={tx_id}&status={UNDECIDED|VALID|INVALID}`` + `endpoint <#get--blocks?tx_id=tx_id&status=UNDECIDED|VALID|INVALID>`_. + + + **Example request**: + + .. sourcecode:: http + + GET /api/v1/blocks HTTP/1.1 Host: example.com **Example response**: .. sourcecode:: http - HTTP/1.1 200 OK - Content-Type: application/json + HTTP/1.1 400 Bad Request - [ - "../transactions/2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e/outputs/0", - "../transactions/2d431073e1477f3073a4693ac7ff9be5634751de1b8abaa1f4e19548ef0b4b0e/outputs/1" - ] + :statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks`` without the ``block_id``. - :statuscode 200: A list of outputs were found and returned in the body of the response. - :statuscode 400: The request wasn't understood by the server, e.g. the ``owner_after`` querystring was not included in the request. +.. http:get:: /api/v1/blocks?tx_id={tx_id}&status={UNDECIDED|VALID|INVALID} + + Retrieve a list of ``block_id`` with their corresponding status that contain a transaction with the ID ``tx_id``. + + Any blocks, be they ``UNDECIDED``, ``VALID`` or ``INVALID`` will be + returned if no status filter is provided. + + .. note:: + In case no block was found, an empty list and an HTTP status code + ``200 OK`` is returned, as the request was still successful. + + :query string tx_id: transaction ID *(required)* + :query string status: Filter blocks by their status. One of ``VALID``, ``UNDECIDED`` or ``INVALID``. + + **Example request**: + + .. literalinclude:: samples/get-block-txid-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-block-txid-response.http + :language: http + + :resheader Content-Type: ``application/json`` + + :statuscode 200: A list of blocks containing a transaction with ID ``tx_id`` was found and returned. + :statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/blocks``, without defining ``tx_id``. + + +Votes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. http:get:: /api/v1/votes?block_id={block_id} + + Retrieve a list of votes for a certain block with ID ``block_id``. + To check for the validity of a vote, a user of this endpoint needs to + perform the `following steps: `_ + + 1. Check if the vote's ``node_pubkey`` is allowed to vote. + 2. Verify the vote's signature against the vote's body (``vote.vote``) and ``node_pubkey``. + + + :query string block_id: The block ID to filter the votes. + + **Example request**: + + .. literalinclude:: samples/get-vote-request.http + :language: http + + **Example response**: + + .. literalinclude:: samples/get-vote-response.http + :language: http + + :resheader Content-Type: ``application/json`` + + :statuscode 200: A list of votes voting for a block with ID ``block_id`` was found and returned. + :statuscode 400: The request wasn't understood by the server, e.g. just requesting ``/votes``, without defining ``block_id``. Determining the API Root URL @@ -190,18 +413,18 @@ the HTTP API publicly accessible. If the API endpoint is publicly accessible, then the public API Root URL is determined as follows: -- The public IP address (like 12.34.56.78) - is the public IP address of the machine exposing - the HTTP API to the public internet (e.g. either the machine hosting - Gunicorn or the machine running the reverse proxy such as Nginx). +- The public IP address (like 12.34.56.78) + is the public IP address of the machine exposing + the HTTP API to the public internet (e.g. either the machine hosting + Gunicorn or the machine running the reverse proxy such as Nginx). It's determined by AWS, Azure, Rackspace, or whoever is hosting the machine. -- The DNS hostname (like apihosting4u.net) is determined by DNS records, - such as an "A Record" associating apihosting4u.net with 12.34.56.78 +- The DNS hostname (like example.com) is determined by DNS records, + such as an "A Record" associating example.com with 12.34.56.78 -- The port (like 9984) is determined by the ``server.bind`` setting - if Gunicorn is exposed directly to the public Internet. - If a reverse proxy (like Nginx) is exposed directly to the public Internet - instead, then it could expose the HTTP API on whatever port it wants to. - (It should expose the HTTP API on port 9984, but it's not bound to do +- The port (like 9984) is determined by the ``server.bind`` setting + if Gunicorn is exposed directly to the public Internet. + If a reverse proxy (like Nginx) is exposed directly to the public Internet + instead, then it could expose the HTTP API on whatever port it wants to. + (It should expose the HTTP API on port 9984, but it's not bound to do that by anything other than convention.)