aboutsummaryrefslogtreecommitdiff
path: root/api/API-structure-implementation-notes.org
blob: 7763236569bcc0bcedbbabb2971826e3dc93496e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#+STARTUP: content
#+TITLE: API Structure Implementation Notes

* Introduction

This document is subservient to the following documents:
- [[./alternative-API-structure.md][Notes on the API]]
- [[./questions-to-ask-GN.md][Questions to ask GN]]

If there are any conflicts, refer to the documents above for clarification. This
simply follows those documents, and might thus be out of sync from time to time.

This document is mostly for those concerned with the implementation of the API.
End users of the API should probably concern themselves with the other document,
though that is not to say they will not find useful information here.

* Routing

It is possible to have separate API versions: we could make use of blueprints
for this and flask's ~add_url_rule~. With this, we should be able to reuse
existing code, writing new code for only the endpoints that might need them.

For example, we could have a file =gn3/api/version02.py= with
content like:

#+BEGIN_SRC python
  from flask import url_for, Blueprint

    from wqflask import species
    from wqflask import populations
    ...

    v2 = Blueprint("v2", __name__)

    @v2.route("/")
    @v2.route("/info")
    def info():
        """Information for the root of the V2 endpoints"""
        return {
            "name": "GeneNetwork REST API",
            "version": "2.0",
            "comment": "This is the official REST API for the GeneNetwork service hosted at https://genenetwork.org/",
            "license": {
                "source code": "AGPL"
            },
            "note": "work in progress (WIP)",
            "see also": "https://genenetwork.org/api/2.0/meta",
            "next level": url_for("api.v2.species.index"), 
            "next level options": url_for("api.v2.index")
        }

    def index():
        """The index of the URIs accessible from this level of the API."""
        return {
            "API": {
                url_for(rule.endpoint): rule.endpoint.__doc__
                for rule in v2.url_map.iter_rules()
            }
        }

    v2.add_url_rule("/species", endpoint=species.index, methods=["GET"])
    v2.add_url_rule("/<species>", endpoint=species.species_info, methods=["GET"])
    v2.add_url_rule("/<species>/populations",
                    endpoint=populations.index,
                    methods=["GET"])
    v2.add_url_rule("/<species>/<population>",
                    endpoint=populations.population,
                    methods=["GET"])
    ...
#+END_SRC

and that would then be registered with the main application with something like:

#+BEGIN_SRC python
  # file gn3/app.py
  ...

  def create_app(...):
      ...
      from api.version02 import v2
      ...
      app.register_blueprint(v2, url_prefix="/api/2.0")
      ...
#+END_SRC

The code above demonstrates the idea, but will probably need some cleanup for
real-world use.

Some url endpoints, especially  =.../index= endpoint, will need for the final
URI's to be computed from the available data, e.g. for =/species/index= we have
eleven (11) species listed in the proposed documentation, but the underlying
data could change, if say, a new species is added to the system.