* feat: remove deprecated /api/submit endpoint * chore: remove unused imports * test: test api_submit_tombstone view
322 lines
16 KiB
HTML
322 lines
16 KiB
HTML
{# Copyright The IETF Trust 2007, All Rights Reserved #}
|
|
{% extends "base.html" %}
|
|
{% load static %}
|
|
{% block title %}API Notes{% endblock %}
|
|
{% block content %}
|
|
<h1>Datatracker API Notes</h1>
|
|
<div class="bio-text">
|
|
<h2 id="framework">Framework API</h2>
|
|
<p>
|
|
This section describes the autogenerated read-only API towards the database tables. See also
|
|
the
|
|
<a href="{% url 'ietf.submit.views.api_submission' %}">Internet-Draft submission API description</a>
|
|
and the
|
|
<a href="#iesg-position-api">IESG ballot position API description</a>
|
|
</p>
|
|
<p>
|
|
The datatracker API uses
|
|
<a href="https://django-tastypie.readthedocs.org/">tastypie</a>
|
|
to generate an API which mirrors the Django ORM (Object Relational Mapping)
|
|
for the database. Each Django model class maps down to the SQL database
|
|
tables and up to the API. The Django models classes are defined in the
|
|
models.py files of the datatracker. Browse the <a href="https://github.com/ietf-tools/datatracker">code tree</a>
|
|
for the models file in each app (such as <a href="https://github.com/ietf-tools/datatracker/blob/main/ietf/doc/models.py">ietf/doc/models.py</a>,
|
|
<a href="https://github.com/ietf-tools/datatracker/blob/main/ietf/group/models.py">ietf/group/models.py</a>, …).
|
|
</p>
|
|
<p>
|
|
The API top endpoint is at
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}">{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}</a>.
|
|
The top
|
|
endpoint lists inferior endpoints, and thus permits some autodiscovery,
|
|
but there's really no substitute for looking at the actual ORM model classes.
|
|
Comparing a class in <code>models.py</code> with the equivalent endpoint may give
|
|
some clue (note that in the case of Group, it's a subclass of <code>GroupInfo</code>):
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/group/group/">{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/group/group/</a>
|
|
</li>
|
|
<li>
|
|
<a href="https://github.com/ietf-tools/datatracker/blob/main/ietf/group/models.py">
|
|
ietf/group/models.py
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
Data is currently provided in JSON and XML format. Adding new formats is
|
|
fairly easy, if it should be found desirable.
|
|
</p>
|
|
<h3 id="framework-documents">Framework API: Documents</h3>
|
|
<p>
|
|
Documents are listed at
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/">{% url 'ietf.api.views.top_level' %}/doc/document/</a>.
|
|
</p>
|
|
<p>
|
|
In general, individual database objects are represented in the API with a path
|
|
composed of the model collection, the object name, and the object key. Most
|
|
objects have simple numerical keys, but documents have the document name as
|
|
key. Take <code>draft-ietf-eppext-keyrelay</code>. Documents have a model <code>Document</code> which
|
|
is described in the <code>doc</code> <code>models.py</code> file. Assembling the path components
|
|
<code>doc</code>, <code>document</code> (lowercase!) and <code>draft-ietf-eppext-keyrelay</code>, we get the
|
|
URL:
|
|
</p>
|
|
<p>
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/draft-ietf-eppext-keyrelay/">
|
|
{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/draft-ietf-eppext-keyrelay/
|
|
</a>
|
|
</p>
|
|
<p>
|
|
If you instead do a search for this document, you will get a machine-readable
|
|
search result, which is composed of some meta-information about the search,
|
|
and a list with one element:
|
|
</p>
|
|
<p>
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?name=draft-ietf-eppext-keyrelay">
|
|
api/v1/doc/document/?name=draft-ietf-eppext-keyrelay
|
|
</a>
|
|
</p>
|
|
<p>
|
|
To search for documents based on state, you need to know that documents have
|
|
multiple orthogonal states:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
If a document has an rfc-editor state, you can select for it by asking for, e.g.,
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?limit=0&name__contains=-v6ops-&states__type__slug__in=draft-rfceditor">
|
|
v6ops documents which match <code>states__type__slug__in=draft-rfceditor</code>
|
|
</a>
|
|
</li>
|
|
<li>
|
|
If a document has an IESG state, you can select for it by asking for, e.g.,
|
|
<a href="{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?name__contains=-v6ops&states__type__slug__in=draft-iesg">
|
|
v6ops documents which match <code>states__type__slug__in=draft-iesg</code>
|
|
</a>
|
|
</li>
|
|
<li>
|
|
If a document has a WG state, you can select for it by asking for
|
|
documents which match <code>states__type__slug__in=draft-stream-ietf</code>
|
|
(but without additional filters, that's going to be a lot of documents)
|
|
</li>
|
|
<li>
|
|
States which match <code>states__type__slug__in=draft</code> describe the basic
|
|
Active/Expired/Dead whatever state of the Internet-Draft.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
You could use this in at least two alternative ways:
|
|
</p>
|
|
<ol>
|
|
<li>
|
|
You could either fetch and remember the different state groups of interest to you
|
|
with queries like
|
|
<pre>
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/state/?format=json&limit=0&type__slug__in=draft-rfceditor'
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/state/?format=json&limit=0&type__slug__in=draft-iesg'
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/state/?format=json&limit=0&type__slug__in=draft-stream-ietf'
|
|
</pre>
|
|
and then match the listed "resource_uri" of the results to the states listed for each
|
|
document when you ask for
|
|
<pre>
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?limit=0&name__contains=-v6ops-'
|
|
</pre>
|
|
</li>
|
|
<li>
|
|
Or alternatively you could do a series of queries asking for matches to the RFC Editor
|
|
state first, then the IESG state, then the Stream state, and exclude earlier hits:
|
|
<pre>
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?limit=0&name__contains=-v6ops-&states__type__slug__in=draft-rfceditor' ...
|
|
$ curl '{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.views.top_level' %}/doc/document/?limit=0&name__contains=-v6ops-&states__type__slug__in=draft-iesg' ...
|
|
</pre>
|
|
etc.
|
|
</li>
|
|
</ol>
|
|
<h2 id="simplified-documents">Simplified Documents API</h2>
|
|
<p>
|
|
A simplified Documents API, intended for cases where only a limited set of
|
|
document attributes are necessary for an application is
|
|
available for all documents at the relative url <code>doc.json</code>, e.g.,
|
|
<code><a class="text-reset" href="{% url 'ietf.doc.views_doc.document_json' name='draft-ietf-poised95-std-proc-3' %}">{% url 'ietf.doc.views_doc.document_json' name='draft-ietf-poised95-std-proc-3' %}</a></code>.
|
|
You can also specify an RFC: <code><a class="text-reset" href="{% url 'ietf.doc.views_doc.document_json' name='rfc2026' %}">{% url 'ietf.doc.views_doc.document_json' name='rfc2026' %}</a></code>.
|
|
No API key is needed to access this.
|
|
</p>
|
|
<p>
|
|
The simplified document API takes no parameters, and is invoked with a HTTP GET.
|
|
</p>
|
|
<h2 id="iesg-position-api">IESG Ballot Position API</h2>
|
|
<p>
|
|
A simplified IESG ballot position interface, intended for automation, is
|
|
available at <code>{% url 'ietf.doc.views_ballot.api_set_position' %}</code>. Access is limited to area directors.
|
|
</p>
|
|
<p>
|
|
The interface requires the use of a personal API key, which can be created at
|
|
<a href="{% url 'ietf.ietfauth.views.apikey_index' %}">{% url 'ietf.ietfauth.views.apikey_index' %}</a>
|
|
</p>
|
|
<p>
|
|
The ballot position API takes the following parameters:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>apikey</code> (required) which is the personal API key hash
|
|
</li>
|
|
<li>
|
|
<code>doc</code> (required) which is the balloted document name
|
|
</li>
|
|
<li>
|
|
<code>position</code> (required) which is the position slug, one of:
|
|
<code>yes</code>, <code>noobj</code>, <code>block</code>, <code>discuss</code>, <code>abstain</code>, <code>recuse</code>, <code>norecord</code>
|
|
.
|
|
</li>
|
|
<li>
|
|
<code>discuss</code> (required if position is <code>discuss</code>) which is the discuss text
|
|
</li>
|
|
<li>
|
|
<code>comment</code> (optional) which is comment text
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
It returns an appropriate http result code, and a brief explanatory text message.
|
|
</p>
|
|
<p>
|
|
Here is an example:
|
|
</p>
|
|
<pre>
|
|
$ curl -S -F "apikey=AwAAABVR3D5GHkVMhspKSxBCVknGMmqikNIhT85kSnghjaV_pYy26WV92mm-jpdi" -F "doc=draft-ietf-lamps-eai-addresses" -F "position=noobj" -F "comment=Comment text" {{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.doc.views_ballot.api_set_position' %}
|
|
Done
|
|
</pre>
|
|
<h2 id="session-video-url-api">Set Session Video URL</h2>
|
|
<p>
|
|
This interface is intended for Meetecho, to provide a way to set the
|
|
URL of a video recording for a given session. It is available at
|
|
<code>{% url 'ietf.meeting.views.api_set_session_video_url' %}</code>.
|
|
Access is limited to recording managers.
|
|
</p>
|
|
<p>
|
|
The interface requires the use of a personal API key, which can be created at
|
|
<a href="{% url 'ietf.ietfauth.views.apikey_index' %}">{% url 'ietf.ietfauth.views.apikey_index' %}</a>
|
|
</p>
|
|
<p>
|
|
The ballot position API takes the following parameters:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>apikey</code> (required) which is the personal API key hash
|
|
</li>
|
|
<li>
|
|
<code>meeting</code> (required) which is the meeting number
|
|
</li>
|
|
<li>
|
|
<code>group</code> (required) which is the group acronym
|
|
</li>
|
|
<li>
|
|
<code>item</code> (required) which is the chronological sequence number of the session (1 for a group's first session, 2 for the second, etc.)
|
|
</li>
|
|
<li>
|
|
<code>url</code> (required) which is the url that points to the video recording
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
It returns an appropriate http result code, and a brief explanatory text message.
|
|
</p>
|
|
<p>
|
|
Here is an example:
|
|
</p>
|
|
<pre>
|
|
$ curl -S -F "apikey=DgAAAMLSi3coaE5TjrRs518xO8eBRlCmFF3eQcC8_SjUTtRGLGiJh7-1SYPT5WiS" -F "meeting=101" -F "group=mptcp" -F "item=1" -F "url=https://foo.example/beer/mptcp" {{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.meeting.views.api_set_session_video_url' %}
|
|
Done
|
|
</pre>
|
|
<h2 id="openid-connect">OpenID Connect</h2>
|
|
<p>
|
|
The datatracker supports
|
|
<a href="https://openid.net/connect/">OpenID Connect</a>,
|
|
but
|
|
not dynamic registration. The OpenID Connect Issuer is
|
|
<code>{{ settings.IDTRACKER_BASE_URL }}{% url 'ietf.api.urls.oidc_issuer' %}</code>
|
|
</p>
|
|
<h2 id="datatracker-version">Datatracker Version</h2>
|
|
<p>
|
|
The datatracker version and release/patch date is available as a JSON blob at
|
|
<code>
|
|
<a href="{% url 'ietf.api.views.version' %}">
|
|
{% url 'ietf.api.views.version' %}
|
|
</a>
|
|
</code>.
|
|
</p>
|
|
<h2 id="personal-api-keys">
|
|
Personal API Keys
|
|
</h2>
|
|
<p>
|
|
The datatracker has some API endpoints that uses Personal API keys,
|
|
rather than having general access or requiring username/password
|
|
login, see for example details for
|
|
<code>{% url 'ietf.doc.views_ballot.api_set_position' %}</code>
|
|
<a href="#iesg-position-api">above</a>.
|
|
Personal API keys are available from your
|
|
<a href="{% url 'ietf.ietfauth.views.apikey_index' %}">
|
|
Account API Keys
|
|
</a>
|
|
page when you are logged in.
|
|
</p>
|
|
<p>
|
|
Personal API keys have some characteristics you should be aware of:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
Each API key is valid only for a specific endpoint. If you try to use a key for
|
|
a different API endpoint than it's created for, it will not work.
|
|
</li>
|
|
<li>
|
|
The API keys will cause you to be given access with the datatracker
|
|
roles you have, thus giving you appropriate access to the various
|
|
API endpoints according to the role limitations indicated for each
|
|
endpoint.
|
|
</li>
|
|
<li>
|
|
An API key will only give you access to its related endpoint if you have logged
|
|
in to the datatracker using your regular login and password during the last
|
|
{{ settings.UTILS_APIKEY_GUI_LOGIN_LIMIT_DAYS }} days. If you receive the
|
|
error message "<code>Too long since last regular login</code>" you should do
|
|
a regular login in order to activate access.
|
|
</li>
|
|
</ul>
|
|
<h2 id="signing-keys">
|
|
Signing Keys
|
|
</h2>
|
|
<p>
|
|
When sending notifications to other APIs, the datatracker may sign
|
|
information with a
|
|
<a href="{% url 'ietf.doc.views_doc.document_html' name='rfc7515' %}">
|
|
RFC
|
|
7515: JSON Web Signature (JWS)
|
|
</a>,
|
|
using a public/private keypair with
|
|
this public key:
|
|
</p>
|
|
<p>
|
|
<code>{{ key.export_public }}</code>
|
|
</p>
|
|
<p>
|
|
or alternatively:
|
|
</p>
|
|
<pre>{{ key.export_to_pem }}</pre>
|
|
<p>
|
|
To verify a signature and get the verified data using Python with the
|
|
<a href="https://jwcrypto.readthedocs.io/en/latest/">
|
|
jwcrypto
|
|
</a>
|
|
module,
|
|
you could do:
|
|
</p>
|
|
<pre>
|
|
from jwcrypto import jwk, jws
|
|
|
|
# ... receive json web signed data as 'data', used below ...
|
|
|
|
key = jwk.JWK()
|
|
key.import_from_pem(API_PUBLIC_KEY_PEM) # the key above
|
|
jwstoken = jws.JWS()
|
|
jwstoken.deserialize(data)
|
|
jwstoken.verify(key)
|
|
payload = jwstoken.payload
|
|
</pre>
|
|
</div>
|
|
{% endblock %} |