Skip to content

Add optional OpenAPI YAML view#766

Merged
sobolevn merged 12 commits intowemake-services:masterfrom
zeel2104:feature/openapi-yaml-view
Apr 5, 2026
Merged

Add optional OpenAPI YAML view#766
sobolevn merged 12 commits intowemake-services:masterfrom
zeel2104:feature/openapi-yaml-view

Conversation

@zeel2104
Copy link
Copy Markdown
Contributor

I have made things!

AI Policy

  • I have read the AI Policy
    and I agree to follow it
  • I have disclosed AI usage in this PR,
    if any AI / LLM / coding agent was participating in the making of this PR
  • I have removed any "Co-Authored-By" lines that attribute coding agents
    and I have carefully manually reviewed the final result produced by the AI

Checklist

  • I have double checked that there are no unrelated changes in this pull request (old patches, accidental config files, etc)
  • I have created at least one test case for the changes I have made
  • I have updated the documentation for the changes I have made

Related issues

Summary

This PR adds support for serving the OpenAPI schema as openapi.yaml.

The new YAML view mirrors the existing openapi.json behavior and is only
available when msgspec is installed, using msgspec.yaml to serialize the
schema.

Changes

  • added OpenAPIYamlView
  • added a YAML dumping helper based on msgspec.yaml.encode
  • exported the YAML view only when msgspec is installed
  • added the openapi.yaml route in the test app conditionally
  • added unit and integration tests for the YAML endpoint
  • updated OpenAPI docs and examples to mention openapi.yaml

Testing

pytest --no-cov tests/test_unit/test_openapi/test_views.py tests/test_integration/test_openapi/test_views.py

Comment thread django_test_app/server/urls.py Outdated
from server.apps.openapi.config import get_config

try:
from dmr.openapi.views import OpenAPIYamlView
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should always be available in our test app

Comment thread dmr/internal/yaml.py Outdated

def yaml_dumps(schema: object) -> str:
"""Serialize schema to a decoded YAML string."""
return _yaml_dumps(schema)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need _yaml_dumps? can we just directly use msgspec?

Comment thread dmr/openapi/views/__init__.py Outdated
Comment on lines +10 to +11
with suppress(ImportError):
from dmr.openapi.views.yaml import OpenAPIYamlView as OpenAPIYamlView
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
with suppress(ImportError):
from dmr.openapi.views.yaml import OpenAPIYamlView as OpenAPIYamlView

do not import it here, if it needs an expra dependency

]

# openapi: {"openapi_url": "/docs/openapi.json/", "use_urlpatterns": true} # noqa: ERA001
# openapi: {"openapi_url": "/docs/openapi.yaml/", "use_urlpatterns": true} # noqa: ERA001, E501
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, don't change this

Copy link
Copy Markdown
Collaborator

@kondratevdev kondratevdev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please make sure that you have checked all the examples and documentation accurately.

Comment thread django_test_app/server/urls.py Outdated
path('docs/stoplight/', StoplightView.as_view(schema), name='stoplight'),
]

urlpatterns.append(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, move it to previous urlpatterns section

urlpatterns = [
    path(router.prefix, include((router.urls, 'server'), namespace='api')),
    path('docs/openapi.json/', OpenAPIJsonView.as_view(schema), name='openapi'),
    path('docs/redoc/', RedocView.as_view(schema), name='redoc'),
    path('docs/scalar/', ScalarView.as_view(schema), name='scalar'),
    path('docs/swagger/', SwaggerView.as_view(schema), name='swagger'),
    path('docs/stoplight/', StoplightView.as_view(schema), name='stoplight'),
    path('docs/openapi.yaml/', OpenAPIYamlView.as_view(schema), name='openapi_yaml')
]

Comment on lines +90 to +96
path(
'docs/openapi.yaml/',
OpenAPIYamlView.as_view(schema),
name='openapi-yaml',
),
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
path(
'docs/openapi.yaml/',
OpenAPIYamlView.as_view(schema),
name='openapi-yaml',
),
)

Comment thread dmr/internal/yaml.py Outdated
@@ -0,0 +1,5 @@
import msgspec
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sobolevn I think we should move it to plugins/msgspec folder, because we need try: ... except: condition for msgspec import

Comment thread dmr/internal/yaml.py Outdated
@@ -0,0 +1,5 @@
import msgspec

def yaml_dumps(schema: object) -> str:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def yaml_dumps(schema: object) -> str:
def yaml_dumps(schema: 'ConvertedSchema') -> 'DumpedSchema':

Comment thread dmr/openapi/views/yaml.py Outdated
Comment on lines +13 to +14
This view mirrors :class:`~dmr.openapi.views.json.OpenAPIJsonView`,
but renders the converted schema using ``msgspec.yaml``.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This view mirrors :class:`~dmr.openapi.views.json.OpenAPIJsonView`,
but renders the converted schema using ``msgspec.yaml``.
Produces a YAML representation of the :class:`~dmr.openapi.objects.OpenAPI`
specification that can be used by API documentation tools
and client code generators.

from dmr.test import DMRClient

try:
from dmr.openapi.views.yaml import OpenAPIYamlView
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must check yaml_dumps import, not view

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_json_returns_correct_structure(dmr_client: DMRClient) -> None:

OpenAPIYamlView is None,
reason='`msgspec` is required for OpenAPI YAML endpoint',
)
def test_yaml_endpoint_returns_correct_structure(dmr_client: DMRClient) -> None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def test_yaml_endpoint_returns_correct_structure(dmr_client: DMRClient) -> None:
def test_yaml_returns_correct_structure(dmr_client: DMRClient) -> None:

Comment on lines +50 to +51
assert OpenAPIYamlView is not None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
assert OpenAPIYamlView is not None

Comment thread django_test_app/server/urls.py Outdated
from server.apps.models_example import urls as models_example_urls
from server.apps.negotiations import urls as negotiations_urls
from server.apps.openapi.config import get_config
from dmr.openapi.views.yaml import OpenAPIYamlView
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from dmr.openapi.views.yaml import OpenAPIYamlView
from dmr.openapi.views import OpenAPIYamlView

You need to make re-export (check __init__.py

StoplightView,
SwaggerView,
)
from dmr.openapi.views.yaml import OpenAPIYamlView
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
from dmr.openapi.views.yaml import OpenAPIYamlView
from dmr.openapi.views import OpenAPIYamlView

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 5, 2026

Merging this PR will not alter performance

✅ 5 untouched benchmarks


Comparing zeel2104:feature/openapi-yaml-view (fb4a900) with master (94dd7fa)

Open in CodSpeed

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (94dd7fa) to head (fb4a900).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #766   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          333       334    +1     
  Lines        13085     13111   +26     
  Branches       413       413           
=========================================
+ Hits         13085     13111   +26     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sobolevn sobolevn merged commit 12b8701 into wemake-services:master Apr 5, 2026
27 checks passed
@sobolevn
Copy link
Copy Markdown
Member

sobolevn commented Apr 5, 2026

@zeel2104 thanks a lot! Great work!

I fixed some minor things and merged it.
This change is comming in 0.5.0 :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support openapi.yaml

3 participants