mirror of
https://github.com/inventree/InvenTree.git
synced 2026-02-02 03:14:56 +00:00
feat(backend): extend schema intro (#10628)
* small refactor * add inventree vendor extension * bump api version * Add control over schema to settings * add more details * disable config as requested * adjust 3.14 diff * cleanup diff * add docs on the new feature * revert bumping of api version - there is no cahnge by default
This commit is contained in:
@@ -119,6 +119,20 @@ The translation process is as follows:
|
||||
|
||||
The [API version]({{ sourcefile("src/backend/InvenTree/InvenTree/api_version.py") }}) needs to be bumped every time when the API is changed.
|
||||
|
||||
### Understanding API shape
|
||||
|
||||
While the default Open API schema generation provides a good overview of the API endpoints, it does not provide insights into the shape of the underlying API (serializer) code.
|
||||
|
||||
The default schema generation cli command `invoke dev.schema` / endpoint `/api/schema/` can be enhanced by setting the schema generation level in the config file or via the [debugging environment variable or config value](../start/config.md#debugging-and-logging-options) `INVENTREE_SCHEMA_LEVEL`.
|
||||
|
||||
At level 1 only simple attributes describing the underlying Django Rest Framework API view of a endpoint are added under the `x-inventree-meta` key.
|
||||
|
||||
At level 2 details about the inheritance of the view (key `x-inventree-components`) and model (key `x-inventree-model`) are added. This allows to trace back the view to the underlying serializer and model and ensure naming of endpoints is consistent with the data model.
|
||||
|
||||
!!! note "For experiments only"
|
||||
There are no CI or system checks to use these additional attributes yet. This is an experimental feature to help developers understand the API shape and how it changes better.
|
||||
|
||||
|
||||
## Environment
|
||||
|
||||
### Software Versions
|
||||
|
||||
@@ -100,6 +100,7 @@ The following debugging / logging options are available:
|
||||
| INVENTREE_JSON_LOG | json_log | log as json | False |
|
||||
| INVENTREE_WRITE_LOG | write_log | Enable writing of log messages to file at config base | False |
|
||||
| INVENTREE_CONSOLE_LOG | console_log | Enable logging to console | True |
|
||||
| INVENTREE_SCHEMA_LEVEL | schema.level | Set level of added schema extensions detail (0-3) 0 = including no additional detail | 0 |
|
||||
|
||||
### Debug Mode
|
||||
|
||||
|
||||
@@ -89,12 +89,13 @@ class ExtendedAutoSchema(AutoSchema):
|
||||
operation['requestBody'] = request_body
|
||||
self.method = original_method
|
||||
|
||||
parameters = operation.get('parameters', [])
|
||||
|
||||
# If pagination limit is not set (default state) then all results will return unpaginated. This doesn't match
|
||||
# what the schema defines to be the expected result. This forces limit to be present, producing the expected
|
||||
# type.
|
||||
pagination_class = getattr(self.view, 'pagination_class', None)
|
||||
if pagination_class and pagination_class == LimitOffsetPagination:
|
||||
parameters = operation.get('parameters', [])
|
||||
for parameter in parameters:
|
||||
if parameter['name'] == 'limit':
|
||||
parameter['required'] = True
|
||||
@@ -102,7 +103,6 @@ class ExtendedAutoSchema(AutoSchema):
|
||||
# Add valid order selections to the ordering field description.
|
||||
ordering_fields = getattr(self.view, 'ordering_fields', None)
|
||||
if ordering_fields is not None:
|
||||
parameters = operation.get('parameters', [])
|
||||
for parameter in parameters:
|
||||
if parameter['name'] == 'ordering':
|
||||
schema_order = []
|
||||
@@ -117,8 +117,6 @@ class ExtendedAutoSchema(AutoSchema):
|
||||
if search_fields is not None:
|
||||
# Ensure consistent ordering of search fields
|
||||
search_fields = sorted(search_fields)
|
||||
|
||||
parameters = operation.get('parameters', [])
|
||||
for parameter in parameters:
|
||||
if parameter['name'] == 'search':
|
||||
parameter['description'] = (
|
||||
@@ -135,8 +133,57 @@ class ExtendedAutoSchema(AutoSchema):
|
||||
schema['items'] = {'$ref': schema['$ref']}
|
||||
del schema['$ref']
|
||||
|
||||
# Add vendor extensions for custom behavior
|
||||
operation.update(self.get_inventree_extensions())
|
||||
|
||||
return operation
|
||||
|
||||
def get_inventree_extensions(self):
|
||||
"""Add InvenTree specific extensions to the schema."""
|
||||
from rest_framework.generics import RetrieveAPIView
|
||||
from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin
|
||||
|
||||
from data_exporter.mixins import DataExportViewMixin
|
||||
from InvenTree.api import BulkOperationMixin
|
||||
from InvenTree.mixins import CleanMixin
|
||||
|
||||
lvl = settings.SCHEMA_VENDOREXTENSION_LEVEL
|
||||
"""Level of detail for InvenTree extensions."""
|
||||
|
||||
if lvl == 0:
|
||||
return {}
|
||||
|
||||
mro = self.view.__class__.__mro__
|
||||
|
||||
data = {}
|
||||
if lvl >= 1:
|
||||
data['x-inventree-meta'] = {
|
||||
'version': '1.0',
|
||||
'is_detail': any(
|
||||
a in mro
|
||||
for a in [RetrieveModelMixin, UpdateModelMixin, RetrieveAPIView]
|
||||
),
|
||||
'is_bulk': BulkOperationMixin in mro,
|
||||
'is_cleaned': CleanMixin in mro,
|
||||
'is_filtered': hasattr(self.view, 'output_options'),
|
||||
'is_exported': DataExportViewMixin in mro,
|
||||
}
|
||||
if lvl >= 2:
|
||||
data['x-inventree-components'] = [str(a) for a in mro]
|
||||
try:
|
||||
qs = self.view.get_queryset()
|
||||
qs = qs.model if qs is not None and hasattr(qs, 'model') else None
|
||||
except Exception:
|
||||
qs = None
|
||||
|
||||
data['x-inventree-model'] = {
|
||||
'scope': 'core',
|
||||
'model': str(qs.__name__) if qs else None,
|
||||
'app': str(qs._meta.app_label) if qs else None,
|
||||
}
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def postprocess_schema_enums(result, generator, **kwargs):
|
||||
"""Override call to drf-spectacular's enum postprocessor to filter out specific warnings."""
|
||||
|
||||
@@ -1495,6 +1495,9 @@ LOGIN_REDIRECT_URL = '/api/auth/login-redirect/'
|
||||
|
||||
# Configuration for API schema generation / oAuth2
|
||||
SPECTACULAR_SETTINGS = spectacular.get_spectacular_settings()
|
||||
SCHEMA_VENDOREXTENSION_LEVEL = get_setting(
|
||||
'INVENTREE_SCHEMA_LEVEL', 'schema.level', default_value=0, typecast=int
|
||||
)
|
||||
|
||||
OAUTH2_PROVIDER = {
|
||||
# default scopes
|
||||
|
||||
@@ -40,6 +40,10 @@ debug_silk: False
|
||||
debug_silk_profiling: False
|
||||
debug_shell: False
|
||||
|
||||
# Schema generation options
|
||||
#schema:
|
||||
# level: 0 # Level of added schema extensions detail (0-3) 0 = including no additional detail, or use the environment variable INVENTREE_SCHEMA_LEVEL
|
||||
|
||||
# Set to False to disable the admin interface, or use the environment variable INVENTREE_ADMIN_ENABLED
|
||||
#admin_enabled: True
|
||||
|
||||
|
||||
@@ -535,9 +535,9 @@ django-cors-headers==4.9.0 \
|
||||
--hash=sha256:15c7f20727f90044dcee2216a9fd7303741a864865f0c3657e28b7056f61b449 \
|
||||
--hash=sha256:fe5d7cb59fdc2c8c646ce84b727ac2bca8912a247e6e68e1fb507372178e59e8
|
||||
# via -r src/backend/requirements.in
|
||||
django-dbbackup==5.1.0 \
|
||||
--hash=sha256:611291606bf6a80903733a99235963e65236c23bca26c2edca453b928b504c67 \
|
||||
--hash=sha256:66c236bbfa0c9bda33a61d30be8c5961d70fa73fed2fe7f829559ac216354130
|
||||
django-dbbackup==5.1.1 \
|
||||
--hash=sha256:371d82803743f6963d7d6d44ee145472213ddd287c43576ddbc11f2277972c1d \
|
||||
--hash=sha256:bfefa6fcf64a602fd5416bc7fff679509bf7eee35c114eee295730df8e9589c9
|
||||
# via -r src/backend/requirements.in
|
||||
django-error-report-2==0.4.2 \
|
||||
--hash=sha256:1dd99c497af09b7ea99f5fbaf910501838150a9d5390796ea00e187bc62f6c1b \
|
||||
@@ -582,9 +582,9 @@ django-mptt==0.18.0 \
|
||||
--hash=sha256:bfa3f01627e3966a1df901aeca74570a3e933e66809ebf58d9df673e63627afb \
|
||||
--hash=sha256:cf5661357ff22bc64e20d3341c26e538aa54583aea0763cfe6aaec0ab8e3a8ee
|
||||
# via -r src/backend/requirements.in
|
||||
django-oauth-toolkit==3.1.0 \
|
||||
--hash=sha256:10ddc90804297d913dfb958edd58d5fac541eb1ca912f47893ca1e482bb2a11f \
|
||||
--hash=sha256:d5a59d07588cfefa8818e99d65040a252eb2ede22512483e2240c91d0b885c8e
|
||||
django-oauth-toolkit==3.2.0 \
|
||||
--hash=sha256:bd2cd2719b010231a2f370f927dbcc740454fb1d0dd7e7f4138f36227363dc26 \
|
||||
--hash=sha256:c36761ae6810083d95a652e9c820046cde0d45a2e2a5574bbe7202656ec20bb6
|
||||
# via -r src/backend/requirements.in
|
||||
django-otp==1.3.0 \
|
||||
--hash=sha256:5277731bc05b6cdbf96aa84ac46018e30ed5fb248086053b0146f925de059060 \
|
||||
@@ -658,33 +658,33 @@ drf-spectacular==0.29.0 \
|
||||
--hash=sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc \
|
||||
--hash=sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a
|
||||
# via -r src/backend/requirements.in
|
||||
dulwich==0.25.0 \
|
||||
--hash=sha256:14c9aba34e1ac262806174304a5a17a78a0f83d0a6960e506005d3aa1cf9004e \
|
||||
--hash=sha256:1575e7bf93cbc9ae93d6653fe29962357b96a1f5943275ff55cbb772e61359e2 \
|
||||
--hash=sha256:3d342daf24cc544f1ccc7e6cf6b8b22d10a4381c1c7ed2bf0e2024a48be9218f \
|
||||
--hash=sha256:47f0328af2c0e5149f356b27d1ac5b2860049c29bf32d2e5994d33f879909dd6 \
|
||||
--hash=sha256:4a98628ae4150f5084e0e0eab884c967d9f499304ff220f558ebe523868fd564 \
|
||||
--hash=sha256:4b46836c467bd898fd2ff1d4ebe511d2956f7f3f181dccbdde8631d4031cd0fa \
|
||||
--hash=sha256:63846a66254dd89bec7b3df75dda61fc37f9c53aa93cddf46d063a9e1f832634 \
|
||||
--hash=sha256:6ca746bd4f8a6a7b849a759c34e960dd7b6fa573225a571e23ea9c73377175d2 \
|
||||
--hash=sha256:757ab788d2d87d96e4b5e84eaddc32d7b8e5b57a221f43b8cbb694787a9c1b80 \
|
||||
--hash=sha256:7b88ef0402ce2a94db5ae926e6be8048e59e8cdcc889a71e332d0e7bcc59f8b7 \
|
||||
--hash=sha256:83e1cbff47ce1dc7d44a20f624c0d2fcbc6a70a458c5fe8e0f8bbf84f32aeb1c \
|
||||
--hash=sha256:866dcf6103ca4dddf9db5c307700b5b47dd49ddadb63423d957bb24d438a87d2 \
|
||||
--hash=sha256:92cc60a9cfd027b0bbaeb588ab06577d58e2b1a41c824f069bd53544f0cccdf3 \
|
||||
--hash=sha256:97f05e8a38f0e1a872b623e094bd270760318c9ab947ff65359192c9a692bda1 \
|
||||
--hash=sha256:ae6f4c99a3978ff4fb1f537d16435d75a17f97ec84f61e3a9ac2b7b879b4dae8 \
|
||||
--hash=sha256:b074a82f40a3ab4068e2f01697a65b6239db55a3335e5c2e9b2a630601c1aa05 \
|
||||
--hash=sha256:b2eb2c727cfa173a48b65fbfc67b170f47c5b28d483759a1fc26886b01770345 \
|
||||
--hash=sha256:b5459ed202fcc7bdaaf619b4bd2718fc7ac7c5dea9c0be682f7e64bf145749e5 \
|
||||
--hash=sha256:baa84b539fea0e6a925a9159c3e0a1d08cceeea5260732b84200e077444a4b0e \
|
||||
--hash=sha256:c0bbe69be332d4cee36f628ba5feaf731c6a53dbe1ea1cf40324a4954a92093a \
|
||||
--hash=sha256:c1731f45fd24b05a01ac32dc0f7e96337a3bd78ab33a230b2035a82f624d112e \
|
||||
--hash=sha256:caeb9740f6e0d5a3fa48e1a009dee2f99f47be1836c6bc252022aa25327fcb0e \
|
||||
--hash=sha256:d8ad390efed25a4fad288f80449a2180bfdb17db19bed4916630c01d20084c4b \
|
||||
--hash=sha256:db89094df6567721ec1eae8a70f85afd22e07eefa86a1b11194247407a3426ee \
|
||||
--hash=sha256:e7e9233686fd49c7fa311e1a9f769ce0fa9eb57e546b6ccd88d2dafb5d7cb6bd \
|
||||
--hash=sha256:f9d5710c8dbaefe6254bbefb409c612485e32d983df9a1299459987b13f2ac3f
|
||||
dulwich==0.25.1 \
|
||||
--hash=sha256:06009f7f86cf3d3cdad3ad113c8667b7d2e7bd6606638462dc10f58fc5e647c3 \
|
||||
--hash=sha256:1316bfd979f708a894bb953c6a1618762169ce7b2db0ea58edffb0e1fc3733ce \
|
||||
--hash=sha256:2ffa8166321cf84a1aa31d091c74f11480831347c5a89f8082b2ad519c40d8ae \
|
||||
--hash=sha256:529da7c6dfea3e404a792044f3a45a5eec6d0095f2d3c3f66ab578825a6a5c2d \
|
||||
--hash=sha256:5c394bcfea736b380b1e5490b28f791f21769bae7aa198c4bd200ad7aa94b9bd \
|
||||
--hash=sha256:6c20393b9e68f68bd772d008ad9a0ce92c9e4cbdc98ab04953e3af668b5dd7e1 \
|
||||
--hash=sha256:6d796c5f5c1e3951a7422046419414f88c4bf282ffb29b0e9b5e7ff821a9ac81 \
|
||||
--hash=sha256:7170de4380e1e0fd1016e567fb932d94f28577fc6a259fd2e25bc25fc86a416b \
|
||||
--hash=sha256:7b4534dffe836d5654a54cc4ecaecfd909846f065ae148a6fdde3d8dd8091552 \
|
||||
--hash=sha256:849195ae2cc245ae2e1b2d67859582e923a7e363f5f9ae5212029429762d9901 \
|
||||
--hash=sha256:8c7756d6f22d11da42fc803584edb290b2cd2a72a6460834644349c739dccab1 \
|
||||
--hash=sha256:97dc27f4af966638c3f0146469f4158eefdf7bddf2fcd9512762ecae4a15c500 \
|
||||
--hash=sha256:a70de3b625cd4cfc249bd24dd5292d1409e76e1d45344e83f408be0a24906862 \
|
||||
--hash=sha256:ba06d579e61ac23a3ad61f9853dd3f5c219d1b4a3bfdda2b1e92ff5f2d952655 \
|
||||
--hash=sha256:bd436ddcd904f3410a87073275a4ad24f91e6c45ec32605f30122661aff63b73 \
|
||||
--hash=sha256:bd670ef6716ac98888ebef423addf25aa921d99d7a8e8199bce59aa9c34525dd \
|
||||
--hash=sha256:c10685eb7f8ef6e072709a766325816a2e2c6cc2e1e2d7fc744f4afc019db542 \
|
||||
--hash=sha256:cb69358e22a7241e398273e16c9754c10a1f01a2f4e66eb3272b17be3016554e \
|
||||
--hash=sha256:cd7627ea178d8c132d8c6ddf048f636862f81e73a3b9d71942c6fd0ab0df4190 \
|
||||
--hash=sha256:ce50b588981d30cd700fbf7352eea6f9aed9a9fc2823dda5a7d183a4e13d0ab8 \
|
||||
--hash=sha256:d86d028109b3fe24c1d5f87304f2078ae4b8813e954d742049755161bd14b2e6 \
|
||||
--hash=sha256:ed00537e01eb1533f2f06dab7c266ea166da9d9ffe88104fe81be84facdb9252 \
|
||||
--hash=sha256:efa3922dbf1b9694cf592682f722bbead9eebccc84fa8adf75d3a40b2cd8eb6c \
|
||||
--hash=sha256:f837add96e55f1c55aa992606f766ba531c76f3b313d26ef0fb60cc398bef04d \
|
||||
--hash=sha256:fa6832891409d59f9e4996df308794e20bed266428cc523ffbb6f515ff95fad4 \
|
||||
--hash=sha256:fe517a1a56c69a0dad252c391122d1d7ff063c7eb31066172396976aa99098a0
|
||||
# via -r src/backend/requirements.in
|
||||
et-xmlfile==2.0.0 \
|
||||
--hash=sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa \
|
||||
@@ -1818,15 +1818,15 @@ s3transfer==0.16.0 \
|
||||
--hash=sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe \
|
||||
--hash=sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920
|
||||
# via boto3
|
||||
sentry-sdk==2.48.0 \
|
||||
--hash=sha256:5213190977ff7fdff8a58b722fb807f8d5524a80488626ebeda1b5676c0c1473 \
|
||||
--hash=sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172
|
||||
sentry-sdk==2.49.0 \
|
||||
--hash=sha256:6ea78499133874445a20fe9c826c9e960070abeb7ae0cdf930314ab16bb97aa0 \
|
||||
--hash=sha256:c1878599cde410d481c04ef50ee3aedd4f600e4d0d253f4763041e468b332c30
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# django-q-sentry
|
||||
setuptools==80.9.0 \
|
||||
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
|
||||
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
|
||||
setuptools==80.10.2 \
|
||||
--hash=sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70 \
|
||||
--hash=sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173
|
||||
# via
|
||||
# -r src/backend/requirements.in
|
||||
# django-money
|
||||
|
||||
@@ -631,9 +631,9 @@ rich==14.2.0 \
|
||||
--hash=sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4 \
|
||||
--hash=sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd
|
||||
# via pytest-codspeed
|
||||
setuptools==80.9.0 \
|
||||
--hash=sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922 \
|
||||
--hash=sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c
|
||||
setuptools==80.10.2 \
|
||||
--hash=sha256:8b0e9d10c784bf7d262c4e5ec5d4ec94127ce206e8738f29a437945fbc219b70 \
|
||||
--hash=sha256:95b30ddfb717250edb492926c92b5221f7ef3fbcc2b07579bcd4a27da21d0173
|
||||
# via
|
||||
# -c src/backend/requirements-3.14.txt
|
||||
# -r src/backend/requirements-dev.in
|
||||
|
||||
Reference in New Issue
Block a user