Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ jobs:
- ["3.12", "py312"]
- ["3.13", "py313"]
- ["3.14", "py314"]
- ["3.14", "linkcheck"]

runs-on: ${{ matrix.os[1] }}
name: ${{ matrix.config[1] }}
Expand All @@ -40,5 +41,5 @@ jobs:
- name: Install tox
run: uv tool install tox --with tox-uv

- name: Test
- name: Tests
run: tox r -e ${{ matrix.config[1] }}
2 changes: 2 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Major changes
.............

- Keep the per-page signature anchor and permalink when ``:noindex:`` is set; only the global route registration is skipped. [:pull:`112` by @ggiesen]
- Fixed the direction of the response and request indicators for headers and JSON fields. Added documentation and tests for JSON fields. Added intersphinx to Sphinx configuration. [:issue:`24` by @stevepiercy]


Minor changes
Expand Down Expand Up @@ -46,6 +47,7 @@ Minor changes
- Bumped tornado from 6.5.8 to 6.5.10. [:pull:`134`]
- Bumped uv-build requirement from >=0.12.16,<0.13.0 to >=0.12.19,<0.13.0. [:pull:`138`]
- Updated the smoke test for Sphinx 8.1.3. [:pull:`128` by @stevepiercy]
- Moved linkcheck test to a separate environment so that the ``py314`` environment can be run separately. Refactored :file:`test` folder to :file:`tests`. Removed unused imports from :file:`websocket_test.py`. Added intersphinx to Sphinx configuration. [:pull:`140` by @stevepiercy]


Version 2.0.0
Expand Down
37 changes: 29 additions & 8 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,16 @@ def get_version_from_toml() -> str:

# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinxcontrib.httpdomain', 'sphinxcontrib.autohttp.flask',
'sphinxcontrib.autohttp.flaskqref',
'sphinxcontrib.autohttp.bottle',
'sphinxcontrib.autohttp.tornado',
'sphinx.ext.extlinks']

extensions = [
"sphinx.ext.extlinks",
"sphinx.ext.intersphinx",
"sphinxcontrib.autohttp.bottle",
"sphinxcontrib.autohttp.flask",
"sphinxcontrib.autohttp.flaskqref",
"sphinxcontrib.autohttp.tornado",
"sphinxcontrib.httpdomain",
]

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

Expand Down Expand Up @@ -302,9 +306,26 @@ def get_version_from_toml() -> str:
# Suppress nonlocal image warning
suppress_warnings = ['image.nonlocal_uri']

# -- linkcheck builder configuration ----------------------------------
linkcheck_ignore = [
# Don't check old links to Bitbucket
r'^https://bitbucket\.org/birkenfeld/sphinx-contrib/(issues|pull-requests)/\d+/', # noqa: E501
r"^https://bitbucket\.org/birkenfeld/sphinx-contrib/(issues|pull-requests)/\d+/", # noqa: E501
# The following site has imposed 403 forbidden responses, link is valid
'https://datatracker.ietf.org/doc/html/',
"https://datatracker.ietf.org/doc/html/",
]


# -- sphinx.ext.intersphinx configuration ----------------------------------

# This extension can generate automatic links to the documentation of objects
# in other projects. Usage is simple: whenever Sphinx encounters a
# cross-reference that has no matching target in the current documentation set,
# it looks for targets in the documentation sets configured in
# intersphinx_mapping. A reference like :py:class:`zipfile.ZipFile` can then
# linkto the Python documentation for the ZipFile class, without you having to
# specify where it is located exactly.
#
# https://www.sphinx-doc.org/en/master/usage/extensions/intersphinx.html
intersphinx_mapping = {
"sphinx": ("https://www.sphinx-doc.org/en/master/", None),
}
177 changes: 136 additions & 41 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -331,28 +331,58 @@ Additionally, you may specify custom options to the directives:
Resource Fields
---------------

Inside HTTP resource description directives like :rst:dir:`get`,
reStructuredText field lists with these fields are recognized and formatted
nicely:
Inside HTTP resource description directives such as :rst:dir:`get`, reStructuredText :doc:`field lists <sphinx:usage/restructuredtext/field-lists>` for the following fields are recognized and nicely formatted.

``param``, ``parameter``, ``arg``, ``argument``
Description of URL parameter.

Example:

.. sourcecode:: rst

.. http:post:: /users/(int:user_id)/add/

:param title: the post title
:parameter body: the post body
:arg sticky: whether it's sticky or not
:argument publish: publication date

Rendering:

.. http:post:: /users/(int:user_id)/add/

:param title: the post title
:parameter body: the post body
:arg sticky: whether it's sticky or not
:argument publish: publication date

``queryparameter``, ``queryparam``, ``qparam``, ``query``
Description of parameter passed by request query string.

It optionally can be typed, all the query parameters will have obviously
string types though. But it's useful if there's conventions for it.
It can be typed.
Although all the query parameters will be string types, it's useful if there are conventions for it.

.. versionchanged:: 1.1.9

It can be typed e.g.:
It can be typed, for example:

.. sourcecode:: rst
.. sourcecode:: rst

.. http:get:: /users/(int:user_id)/posts/view

:param string title: the post title
:parameter string body: the post body
:arg boolean sticky: whether it's sticky or not
:argument date publish: publication date

Rendering:

:query string title: the post title
:query string body: the post body
:query boolean sticky: whether it's sticky or not
.. http:get:: /users/(int:user_id)/posts/view

:param string title: the post title
:parameter string body: the post body
:arg boolean sticky: whether it's sticky or not
:argument date publish: publication date

``formparameter``, ``formparam``, ``fparam``, ``form``
Description of parameter passed by request content body, encoded in
Expand All @@ -364,71 +394,136 @@ nicely:
:mimetype:`application/json`.

.. deprecated:: 1.3.0
Use ``reqjsonobj``/``reqjson``/``<jsonobj``/``<json`` and
``reqjsonarr``/``<jsonarr`` instead.

Use ``reqjsonobj``/``reqjson``/``>jsonobj``/``>json`` and
``reqjsonarr``/``>jsonarr`` instead.

.. versionadded:: 1.1.8

.. versionchanged:: 1.1.9

It can be typed e.g.:
It can be typed, for example:

.. sourcecode:: rst

:jsonparam string title: the post title
:jsonparam string body: the post body
:jsonparam boolean sticky: whether it's sticky or not

``reqjsonobj``, ``reqjson``, ``<jsonobj``, ``<json``
Description of a single field of JSON object passed by request body,
encoded in :mimetype:`application/json`. The key difference from ``json`` is
explicitly defined use-case (request/response) of the described object.
``reqjsonobj``, ``reqjson``, ``>jsonobj``, ``>json``
Description of a single field of a JSON object passed in the request body, and encoded in :mimetype:`application/json`.
The key difference from ``json`` is that the request is explicitly defined in the described object.

.. sourcecode:: rst
Using the following JSON object, it can be typed as shown in the subsequent example.

.. code-block:: json

{
"user_id": 1,
"post_id": 2
}

.. code-block:: rst

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:reqjson integer user_id: The user ID.
:>json integer post_id: The post ID.

Rendering:

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:reqjson integer user_id: The user ID.
:>json integer post_id: The post ID.

:<json string title: the post title
:<json string body: the post body
:<json boolean sticky: whether it's sticky or not
Additionally, it can be typed as a JSON object.

.. code-block:: rst

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:reqjson reqjsonobj user_id: The user ID.
:>json >jsonobj post_id: The post ID.

Rendering:

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:reqjson reqjsonobj user_id: The user ID.
:>json >jsonobj post_id: The post ID.

.. versionadded:: 1.3.0

``resjsonobj``, ``resjson``, ``>jsonobj``, ``>json``
Description of a single field of JSON object returned with response body,
encoded in :mimetype:`application/json`.
``resjsonobj``, ``resjson``, ``<jsonobj``, ``<json``
Description of a single field of a JSON object returned in the response body, and encoded in :mimetype:`application/json`.
The key difference from ``json`` is that the response is explicitly defined in the described object.

.. sourcecode:: rst
.. code-block:: rst

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:resjson boolean ok: Operation status.
:<json integer error: Error code.

Rendering:

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:>json boolean ok: Operation status
:resjson boolean ok: Operation status.
:<json integer error: Error code.

Additionally, it can be typed as a JSON object.

.. code-block:: rst

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:resjson resjsonobj ok: Operation status.
:<json <jsonobj error: Error code.

Rendering:

.. http:get:: /users/(int:user_id)/posts/(int:post_id)

:resjson resjsonobj ok: Operation status.
:<json <jsonobj error: Error code.

.. versionadded:: 1.3.0

``reqjsonarr``, ``<jsonarr``
``resjsonarr``, ``>jsonarr``
``reqjsonarr``, ``>jsonarr``,
``resjsonarr``, ``<jsonarr``

Similar to ``<json`` and ``>json`` respectively, but uses for describing
objects schema inside of returned array.
Similar to ``>json`` and ``<json``, respectively, but used for describing
object schema inside of the returned array.

Let's say, the response contains the following data:
Let's say the response contains the following data:

.. sourcecode:: javascript
.. sourcecode:: json

[{"id": "foo", "ok": true}, {"id": "bar", "error": "forbidden", "reason": "sorry"}]
[
{
"id": "foo",
"ok": true
},
{
"id": "bar",
"error": "forbidden",
"reason": "sorry"
}
]

Then we can describe it in the following way:

.. sourcecode:: rst

:>jsonarr boolean ok: Operation status. Not present in case of error
:>jsonarr string id: Object ID
:>jsonarr string error: Error type
:>jsonarr string reason: Error reason
:<jsonarr boolean ok: Operation status. Not present in case of error
:<jsonarr string id: Object ID
:<jsonarr string error: Error type
:<jsonarr string reason: Error reason

.. versionadded:: 1.3.0

.. sourcecode:: rst

:>json boolean status: Operation status

``requestheader``, ``reqheader``, ``>header``
Description of request header field.

Expand Down
20 changes: 10 additions & 10 deletions src/sphinxcontrib/httpdomain/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,28 +277,28 @@ class HTTPResource(ObjectDescription):
names=('jsonparameter', 'jsonparam', 'json'),
typenames=('jsonparamtype', 'jsontype')),
TypedField('requestjsonobject', label=_('Request JSON Object'),
names=('reqjsonobj', 'reqjson', '<jsonobj', '<json'),
typenames=('reqjsonobj', '<jsonobj')),
names=('reqjsonobj', 'reqjson', '>jsonobj', '>json'),
typenames=('reqjsonobj', '>jsonobj')),
TypedField('requestjsonarray', label=_('Request JSON Array of Objects'),
names=('reqjsonarr', '<jsonarr'),
typenames=('reqjsonarrtype', '<jsonarrtype')),
names=('reqjsonarr', '>jsonarr'),
typenames=('reqjsonarrtype', '>jsonarrtype')),
TypedField('responsejsonobject', label=_('Response JSON Object'),
names=('resjsonobj', 'resjson', '>jsonobj', '>json'),
typenames=('resjsonobj', '>jsonobj')),
names=('resjsonobj', 'resjson', '<jsonobj', '<json'),
typenames=('resjsonobj', '<jsonobj')),
TypedField('responsejsonarray', label=_('Response JSON Array of Objects'),
names=('resjsonarr', '>jsonarr'),
typenames=('resjsonarrtype', '>jsonarrtype')),
names=('resjsonarr', '<jsonarr'),
typenames=('resjsonarrtype', '<jsonarrtype')),
TypedField('queryparameter', label=_('Query Parameters'),
names=('queryparameter', 'queryparam', 'qparam', 'query'),
typenames=('queryparamtype', 'querytype', 'qtype')),
GroupedField('formparameter', label=_('Form Parameters'),
names=('formparameter', 'formparam', 'fparam', 'form')),
GroupedField('requestheader', label=_('Request Headers'),
rolename='header',
names=('<header', 'reqheader', 'requestheader')),
names=('>header', 'reqheader', 'requestheader')),
GroupedField('responseheader', label=_('Response Headers'),
rolename='header',
names=('>header', 'resheader', 'responseheader')),
names=('<header', 'resheader', 'responseheader')),
GroupedField('statuscode', label=_('Status Codes'),
rolename='statuscode',
names=('statuscode', 'status', 'code'))
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading