api.rst 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. .. _api-dev:
  2. Developing on the API
  3. ============================================
  4. The FlexMeasures API is the main way that third-parties can automate their interaction with FlexMeasures, so it's highly important.
  5. This is a small guide for creating new versions of the API and its docs.
  6. .. warning:: This guide was written for API versions below v3.0 and is currently out of date.
  7. .. todo:: A guide for endpoint design, e.g. using Marshmallow schemas and common validators.
  8. .. contents:: Table of contents
  9. :local:
  10. :depth: 2
  11. Introducing a new API version
  12. ---------------------
  13. Larger changes to the API, other than fixes and refactoring, should be done by creating a new API version.
  14. In the guide we're assuming the new version is ``v1.1``.
  15. Whether we need a new API version or not, doesn't have a clear set of rules yet.
  16. Certainly backward-incompatible changes should require one, but as you'll see, there is also certain overhead in creating
  17. a new version, so a careful trade-off is advised.
  18. .. note:: For the rest of this guide we'll assume your new API version is ``v1_1``.
  19. Set up new module with routes
  20. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  21. In ``flexmeasures/api`` create a new module (folder with ``__init__.py``\ ).
  22. Copy over the ``routes.py`` from the previous API version.
  23. By default we import all routes from the previous version:
  24. .. code-block:: python
  25. from flexmeasures.api.v1 import routes as v1_routes, implementations as v1_implementations
  26. Set the service listing for this version (or overwrite completely if needed):
  27. .. code-block:: python
  28. v1_1_service_listing = copy.deepcopy(v1_routes.v1_service_listing)
  29. v1_1_service_listing["version"] = "1.1"
  30. Then update and redecorate each API endpoint as follows:
  31. .. code-block:: python
  32. @flexmeasures_api.route("/getService", methods=["GET"])
  33. @as_response_type("GetServiceResponse")
  34. @append_doc_of(v1_routes.get_service)
  35. def get_service():
  36. return v1_implementations.get_service_response(v1_1_service_listing)
  37. Set up a new blueprint
  38. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  39. In the new module's ``flexmeasures/api/v1_1/__init.py__``\ , copy the contents of ``flexmeasures/api/v1/__init.py__`` (previous API version).
  40. Change all references to the version name in the new file (for example: ``flexmeasures_api_v1`` should become ``flexmeasures_api_v1_1``\ ).
  41. In ``flexmeasures/api/__init__.py`` update the version listing in ``get_versions()`` and register a blueprint for the new api version by adding:
  42. .. code-block:: python
  43. from flexmeasures.api.v1_1 import register_at as v1_1_register_at
  44. v1_1_register_at(app)
  45. New or updated endpoint implementations
  46. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  47. Write functionality of new or updated endpoints in:
  48. .. code-block::
  49. flexmeasures/api/v1_1/implementations.py
  50. Utility functions that are commonly shared between endpoint implementations of different versions should go in:
  51. .. code-block::
  52. flexmeasures/api/common/utils
  53. where we distinguish between response decorators, request validators and other utils.
  54. Testing
  55. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  56. If you changed an endpoint in the new version, write a test for it.
  57. Usually, there is no need to copy the tests for unchanged endpoints, if not a major API version is being released.
  58. Test the entire api or just your new version:
  59. .. code-block:: bash
  60. $ pytest -k api
  61. $ pytest -k v1_1
  62. UI Crud
  63. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  64. In ``ui/crud``\ , we support FlexMeasures' in-built UI with Flask endpoints, which then talk to our internal API.
  65. The routes used there point to an API version. You should consider updating them to point to your new version.
  66. Documentation
  67. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  68. In ``documentation/api`` start a new specification ``v1_1.rst`` with contents like this:
  69. .. code-block:: RST
  70. .. _v1_1:
  71. Version 1.1
  72. ===========
  73. Summary
  74. -------
  75. .. qrefflask:: flexmeasures.app:create()
  76. :blueprints: flexmeasures_api, flexmeasures_api_v1_1
  77. :order: path
  78. :include-empty-docstring:
  79. API Details
  80. -----------
  81. .. autoflask:: flexmeasures.app:create()
  82. :blueprints: flexmeasures_api, flexmeasures_api_v1_1
  83. :order: path
  84. :include-empty-docstring:
  85. If you are ready to publish the new specifications, enter your changes in ``documentation/api/change_log.rst`` and update the api toctree in ``documentation/index.rst``
  86. to include the new version in the table of contents.
  87. You're not done. Several sections in the API documentation list endpoints as examples. If you want other developers to use your new API version, make sure those examples reference the latest endpoints. Remember that `Sphinx autoflask <https://sphinxcontrib-httpdomain.readthedocs.io/en/stable/#module-sphinxcontrib.autohttp.flask>`_ likes to prefix the names of endpoints with the blueprint’s name, for example:
  88. .. code-block:: RST
  89. .. autoflask:: flexmeasures.app:create()
  90. :endpoints: flexmeasures_api_v1_1.post_meter_data