Files
galaxy/doc/source/dev/api_guidelines.rst
T
2021-01-13 18:19:29 -05:00

173 lines
7.8 KiB
ReStructuredText

API Design Guidelines
=====================
The following section outlines guidelines related to extending and/or modifying
the Galaxy API. The Galaxy API has been developed over time in an ad-hoc fashion and by
many contributors, so clients SHOULD NOT expect the API will conform to
these guidelines - but developers contributing to the Galaxy API SHOULD follow
these guidelines.
Before Getting Started
~~~~~~~~~~~~~~~~~~~~~~
Developers should familiarize themselves with `HTTP method definitions
<https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9>`__. While Galaxy
follows these imperfectly - a serious effort should be made to use HTTP
methods (GET, POST, PUT, DELETE, etc.) correctly and consistently. More
information about these methods with a focus on RESTful APIs can be found
at https://restfulapi.net/http-methods/.
Developers should also familiarize themselves with the `HTTP status code definitions
<http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>`__. The API responses
should properly set the status code according to the result - in particular
2XX responses should be used for successful requests, 4XX for various
kinds of client errors, and 5XX for the errors on the server side.
Finally, developers should familiarize themselves with `RESTful API design
<https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design>`__.
Again, Galaxy follows generic RESTful guidelines imperfectly, but a serious
effort should be made to design the API as RESTfully and consistently as possible.
Documenting the API
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An API endpoint implementation method should include high-level docstring documentation
for consumption at docs.galaxyproject.org.
API functionality should consume and produce Pydantic_ `models
<https://pydantic-docs.helpmanual.io/usage/models/>`__ with typed and annotated
`fields <https://pydantic-docs.helpmanual.io/usage/types/>`__. This information
will be used to generate detailed OpenAPI_ documentation for APIs in
the near future. Typed models also improve the quality and thoroughness
of the static checking that can be done for the Galaxy backend.
To further document your API and allow other developers to see how it functions,
new API functionality should include functional tests. These functional
tests should be implemented in Python and added to either the API test suite
or the integration test suite. Checkout the :doc:`Writing Tests for Galaxy <writing_tests>`
documentation for more information on developing tests for Galaxy.
.. note::
The Galaxy documentation can be generated by running ``make docs-develop``
from the Galaxy root. Galaxy can be type checked by running ``tox -e mypy``
from the root of Galaxy after tox_ has been configured.
Error Handling
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
API methods should throw a finite number of exceptions
(defined in :mod:`galaxy.exceptions`) and these should subclass
:class:`galaxy.exceptions.MessageException` and not paste/WSGI/FastAPI HTTP exceptions.
When possible, the framework itself should be responsible for catching these exceptions,
setting the status code, and building an error response. Throwing these exceptions
will ensure the API responses are consistent across frameworks and across the API.
These exceptions allow throwers to attach arbitrary extra information.
Error responses should not consist of plain text strings - they should be
dictionaries describing the error and containing the following:
.. code-block: json
{
"status_code": 400,
"err_code": 400007,
"err_msg": "Request contained invalid parameter, action could not be completed.",
"type": "error",
"extra_error_info": "Extra information."
}
The error code (``err_code``) is defined by the exception class
and pulled from ``lig/galaxy/exceptions/error_codes.json``. This JSON
document should be used to add new error conditions or improve
default error messages.
If there is an error processing some part of the request (one item in a list
for instance), the status code should be set to reflect the error and the
partial result may or may not be returned depending on the controller -
this behavior should be documented.
Backward Compatibility
~~~~~~~~~~~~~~~~~~~~~~
Backward compatibility is important and should be maintained when possible.
If changing behavior in a non-backward compatible way please ensure one
of the following holds - there is a strong reason to believe no consumers
depend on the old behavior, the behavior is effectively broken, or the API
method being modified has not been part of a tagged dist release. If these
conditions do not hold, please help the Galaxy release manager ensure
information about the breaking API is highlighted in the Galaxy release
notes.
Whenever functionality needs to be added, removed, or modified that
breaks backward compatibility in a significant way to a component used by
the community - a "dev" variant of the API should be established and
the community should be alerted and given a time frame for when the old
behavior will be replaced with the new behavior.
Design
~~~~~~
Functionality should not be copied and pasted between controllers -
consider refactoring functionality into associated classes or short of
that into mixins_ or into managers (:mod:`galaxy.managers`).
To whatever degree is possible, the Galaxy API controller classes
(found in :mod:`galaxy.webapps.galaxy.api`) should be as lean as
possible. Most of the logic should be pushed into components that
are decoupled from the actual web application and the web framework.
The role of the controller should be simply to adapt the web request
(tied to the web framework) to simple objects (plain Python objects,
Pydantic_ models, or SQLAlchemy models), send these objects to a
Python component lower in the stack, and finally to translate the
response to a web response. This design will ensure that Galaxy
application logic is usable in as many contexts as possible and
decouple the core "business logic" of Galaxy from the web framework
hosting it.
Going forward, we anticipate the most typical way this abstract
advice translates to concrete code flow is that API controllers
in :mod:`galaxy.webapps.galaxy.api` receive or produce Pydantic_
models and pass them to manager components defined in
:mod:`galaxy.managers`. The manager is then responsible for
interacting with the whole backend or specific components to
fullfil the desired request.
Galaxy work contexts provide a way for API requests (and other
components) to describe what they require from the framework
in terms of the request (examples include the Galaxy app, a user
to act on behalf of, or a user with a defined "current history").
These objects describing the web request are passed around rather
haphazardly as an argument named ``trans``. To design API methods
to deal with ``trans`` in the most statically checkable and
rigorous way - please review the docs for :mod:`galaxy.managers.context`.
Examples
~~~~~~~~
A very clean, isolated example of a well documented controller
and well annotated models is the licenses endpoint -
:mod:`galaxy.webapps.galaxy.api.licenses`. A more complicated
endpoint that demonstrates working with a manager and the
Galaxy model backend is the roles endpoint - :mod:`galaxy.webapps.galaxy.api.roles`.
BioBlend
~~~~~~~~
Changes to reflect modifications to the API should be pushed upstream to
the BioBlend_ project if possible.
Longer Term Goals
~~~~~~~~~~~~~~~~~~
- It would be advantageous to have a clearer separation of anonymous and
admin handling functionality.
- Consistent standards for range-based requests, batch requests, filtered
requests, etc... should be established and documented here.
.. _Pydantic: https://pydantic-docs.helpmanual.io/
.. _BioBlend: https://github.com/galaxyproject/bioblend
.. _mixins: http://en.wikipedia.org/wiki/Composition_over_inheritance
.. _tox: https://tox.readthedocs.io/en/latest/
.. _OpenAPI: https://www.openapis.org