Metadata-Version: 2.4
Name: django-asyncdocs
Version: 0.1.1
Summary: Swagger for everything Swagger doesn't cover: interactive, auto-generated docs + a live test console for AsyncAPI specs (WebSocket, SSE, MQTT, or any async protocol).
Author-email: MUHAMMEDHAFEEZ <mohamedhafeez.dev@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs
Project-URL: Repository, https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs
Project-URL: Issues, https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/issues
Keywords: django,asyncapi,websocket,documentation,openapi,swagger
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Intended Audience :: Developers
Classifier: Topic :: Software Development :: Documentation
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: Django>=4.2
Requires-Dist: PyYAML>=6.0
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-django; extra == "test"
Dynamic: license-file

![django-asyncdocs](https://raw.githubusercontent.com/MUHAMMEDHAFEEZ/django-asyncdocs/master/docs/assets/logo-lockup.svg)

*"Swagger for everything Swagger doesn't cover."*

![pypi](https://img.shields.io/pypi/v/django-asyncdocs?color=6f42c1&labelColor=21262d)
![license](https://img.shields.io/badge/license-MIT-6f42c1?labelColor=21262d)
![asyncapi](https://img.shields.io/badge/asyncapi-2.x%20%C2%B7%203.0-6f42c1?labelColor=21262d)
![django](https://img.shields.io/badge/django-4.2%2B-6f42c1?labelColor=21262d)

Full docs, screenshots, and the source live on
[GitHub](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs) — this page is a
plain-markdown version of the same README, since PyPI's renderer doesn't
support the layout GitHub does.

---

Auto-generated, interactive documentation — and a live test console — for
[AsyncAPI](https://www.asyncapi.com/) specs: WebSocket, SSE, MQTT, or any
other async protocol your Django project describes with one. Install it,
point it at a spec file, and get a browsable page with a sidebar of channels,
a payload schema reference, and a "Try it out" console that authorizes,
connects, and lets you trigger a real server-side effect to watch a frame
arrive — all without leaving the page.

Supports **both AsyncAPI dialects** (2.x and 3.0) through one normalizer, so a
spec written either way renders through the exact same templates.

## Screenshots

**Index — one card per registered spec:**

![Index page](https://raw.githubusercontent.com/MUHAMMEDHAFEEZ/django-asyncdocs/master/docs/assets/screenshot-index.png)

**Detail — docs + a live test console:**

![Console page](https://raw.githubusercontent.com/MUHAMMEDHAFEEZ/django-asyncdocs/master/docs/assets/screenshot-console.png)

See it in action (animated): [browsing the index](https://raw.githubusercontent.com/MUHAMMEDHAFEEZ/django-asyncdocs/master/docs/assets/demo-browse.gif)
and [authorizing + connecting](https://raw.githubusercontent.com/MUHAMMEDHAFEEZ/django-asyncdocs/master/docs/assets/demo-console.gif).

## Features

- **Auto-generated docs** — point it at an AsyncAPI YAML file, get a full docs page. Nothing to write by hand, nothing to keep in sync manually.
- **Both AsyncAPI dialects** — 2.x and 3.0 render through the exact same templates via one normalizer, so a spec written either way just works.
- **A real test console** — authorize, connect, and trigger a server-side action to watch a live frame arrive, without leaving the page.
- **Secure by default** — every access denial is a `404`, never a `403` or login redirect, so an unauthorized visitor can't even confirm a spec exists.
- **Multi-tenancy hooks** — two extension points (`TenantResolver`, `TenantSpecFilter`) for projects that already have real tenant isolation to plug in.

## Install

**1. Install the package**

```bash
pip install django-asyncdocs
```

**2. Register it and point it at a spec**

```python
# settings.py
INSTALLED_APPS = [..., "asyncdocs"]

ASYNC_DOCS = {
    "SPECS": {
        "my-channel": {
            "path": BASE_DIR / "apps" / "ws" / "asyncapi.yaml",
            "login_url": "/api/v1/auth/login/",
            "actions": {"send_test": "myproject.docs_actions.send_test"},
        },
    },
}
```

**3. Mount the URLs**

```python
# urls.py
from django.urls import include, path

urlpatterns = [..., path("asyncdocs/", include("asyncdocs.urls"))]
```

Never written an AsyncAPI spec before, or don't have one yet? Start at
[writing-your-first-spec.md](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/writing-your-first-spec.md)
— it builds one from nothing.

Already have a spec?
[getting-started.md](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/getting-started.md)
covers the rest (staff login, the `ENABLED` gate, verifying it without a
browser).

## Documentation

- [Getting started](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/getting-started.md)
- [Writing your first AsyncAPI spec](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/writing-your-first-spec.md)
- [Configuration reference](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/configuration.md)
- [Writing test actions](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/test-actions.md)
- [Security](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/security.md)
- [Multi-tenancy](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/multi-tenancy.md)
- [FAQ / troubleshooting](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/docs/faq.md)

## How it works

**AsyncAPI 2.x vs 3.0, briefly.** One normalizer per dialect produces the
exact same flat shape regardless of which one a spec is written in — the
dialect is recorded once (`asyncapi_version`) and shown as a badge; nothing
downstream branches on it.

**Security, briefly.** Every access denial (failed staff check, IP
allowlist, unknown or tenant-filtered slug) is a `404`, never a `403` or a
login redirect — so a response never confirms a spec exists to someone who
can't see it. The console's token lives in a JS variable for the tab only,
never `localStorage`/`sessionStorage`/a URL, always masked on screen.

**Multi-tenancy, briefly.** Ships no working isolation — every staff user
sees every spec by default, correct for a single-tenant project. Two hooks
(`TenantResolver`, `TenantSpecFilter`) let a project that already has real
tenant isolation plug it in later as a settings change.

Full details for all three: see the
[docs](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/tree/master/docs).

## License

MIT — see [LICENSE](https://github.com/MUHAMMEDHAFEEZ/django-asyncdocs/blob/master/LICENSE).
