Metadata-Version: 2.4
Name: django-allresponses
Version: 0.1.0
Summary: Django response classes for all RFC9110 HTTP status codes
Project-URL: Homepage, https://django-allresponses.x14.nl
Project-URL: Documentation, https://django-allresponses.x14.nl
Project-URL: Repository, https://codeberg.org/michielb/django-allresponses.git
Project-URL: Issues, https://codeberg.org/michielb/django-allresponses/issues
Author-email: "Michiel W. Beijen" <mb@x14.nl>
License-Expression: MIT
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Django
Classifier: Framework :: Django :: 4.2
Classifier: Framework :: Django :: 5.0
Classifier: Framework :: Django :: 5.1
Classifier: Framework :: Django :: 5.2
Classifier: Framework :: Django :: 6.0
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.8
Requires-Dist: django<6.0,>=4.2
Provides-Extra: dev
Requires-Dist: mkdocstrings-python>=2.0; (python_version >= '3.10') and extra == 'dev'
Requires-Dist: pytest-django>=4.5; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ty>=0.0.21; extra == 'dev'
Requires-Dist: zensical>=0.0.11; (python_version >= '3.10') and extra == 'dev'
Description-Content-Type: text/markdown

# django-allresponses

A Django package that provides response classes for all
[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html) HTTP status codes.

## Features

- Response classes for all RFC 9110 HTTP status codes
- Compatible with Django 4.2 LTS and later versions
- Full test coverage
- Type hints included

## Installation

```bash
uv add django-allresponses

# or with pip

pip install django-allresponses
```

## Usage

All response classes in this package are subclasses of Django’s
[`HttpResponse`](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpResponse).
You can use them anywhere you would use a normal `HttpResponse`, and they work
with Django’s middleware and testing tools.

For HTML or other content, use the **HttpResponse**-prefixed classes:

```python
from django_allresponses import HttpResponseOK, HttpResponseNoContent, HttpResponseCreated

def my_view(request):
    # Return a 200 OK response (explicit status)
    return HttpResponseOK("<p>Hello</p>")

    # Or 204 No Content
    return HttpResponseNoContent()
    # Or 201 Created with a Location header
    return HttpResponseCreated(location='/api/resource/123')
```

For JSON APIs, use the **JsonResponse**-prefixed classes (they subclass
Django’s
[`JsonResponse`](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.JsonResponse)
and set the status code for you):

```python
from django_allresponses import JsonResponseOK, JsonResponseCreated, JsonResponseUnauthorized

def api_view(request):
    if not request.user.is_authenticated:
        return JsonResponseUnauthorized({"error": "Authentication required"})
    data = {"id": 123, "name": "Example"}
    return JsonResponseCreated(data, location="/api/items/123")
```

## Why this package?

Basically, because Django has a whole bunch of custom HttpResponse subclasses,
for
[BadRequest](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpResponseBadRequest),
for
[ResponseNotFound](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpResponseNotFound),
for
[ResponseNotModified](https://docs.djangoproject.com/en/stable/ref/request-response/#django.http.HttpResponseNotModified)
and so on.

But for some very standard response codes such as No Content (HTTP 204) and
Created (HTTP 201) there are no subclasses. In RESTy systems I use these
response codes all the time.

It feels very arbitrary that some classes exist and others don't.

Of course I can make my own subclass and use that but I would like Django to
have it built-in. So I opened a discussion about this:

https://forum.djangoproject.com/t/proposal-or-discussion-add-subclasses-for-no-content-and-created-httpresponses/39020

TL;DR: people do not find it is 'worth it' to add these response codes that are
used a lot, because you could just as well write your own, or use the 'generic'
HTTPResponse and add a custom code.

That's all fair, but I do think that custom classes have other benefits too. I
think it's beneficial to list the responses that you can choose from all in one
place, instead of having a specific response for Gone (HTTP 410) but none for
Created.

So I went all maximalist and added a complete list of _all_ RFC9110 HTTP status
codes as subclasses in this django-allresponses module. Many of those will
probably never be used at all, which I think is fine, but at least now you'll
have one easy way to refer to all possible HTTP responses in one go!

Several subclasses add real behaviour on top of the status code, so they are
not just “a status number in a class”. For example: **204 No Content** and
**205 Reset Content** strip the Content-Type header and forbid setting a
response body; **201 Created** requires a `location` and sets the Location
header; **405 Method Not Allowed** requires the list of allowed methods and
sets the Allow header (as required by
[RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html)); **503 Service
Unavailable** accepts an optional `retry_after` keyword (seconds or a datetime)
and sets the Retry-After header. Using these classes keeps your responses
spec-compliant and consistent. Plus the explicit status names also help with
readability of your code!

One last benefit of using this module is that some HTTP status codes changed
name in different RFCs. Django being a seasoned project is using th e 'older'
names for HTTP statuses. Our module uses newer names. For example, Django's
HttpResponsePermanentRedirect returns a 302 by default but 302 is now "Found".
Our HttpResponsePermanentRedirect returns 308, and we _also_ include
HttpResponseFound which returns 302 for when you might need it.

## Development

This project uses `uv` for dependency management and `hatch` for building. A
**Makefile** wraps the common commands (run `make help` for a list).

To set up the development environment:

```bash
# Install uv if you haven't already
pip install uv

# Create a virtual environment and install dependencies
uv venv
source .venv/bin/activate  # On Unix/macOS
# or
.venv\Scripts\activate  # On Windows

# Install dependencies
make install
# Or with dev tools (pytest, pdoc, ruff, ty):  make install-dev
```

### Running tests

Run **from the project root** (the directory that contains `manage.py` and the
Makefile).

```bash
make test          # Django test runner (no extra deps)
make test-pytest   # Pytest (needs: make install-dev)
```

The test suite uses a minimal Django project under `tests/`
(`tests/settings.py` and the `tests` app). Django needs
`DJANGO_SETTINGS_MODULE=tests.settings`, which `manage.py` sets automatically;
pytest uses the same via `pyproject.toml`.

### Building the documentation site

Docstrings on every response class explain when and why to use that status
code; they appear in your editor (e.g. hover) and can be turned into a static
documentation site with [Zensical](https://zensical.org/) (MkDocs-compatible)
and [mkdocstrings](https://mkdocstrings.github.io/).

```bash
make install-deps  # once: install zensical and other dev deps
make docs         # build HTML into site/
make serve-docs   # serve docs in the browser at http://localhost:8080
```

### Type checking

Type checking uses [ty](https://docs.astral.sh/ty/) (Astral’s type checker).
Run from the project root (requires dev deps):

```bash
make install-dev   # once: install ty and other dev deps
make typecheck     # uv run ty check .
```

After `make docs`, open `site/index.html` in a browser, or run
`make serve-docs` to preview with live reload. Source lives in `docs/`;
Zensical writes the built site to `site/` (in `.gitignore`). The project uses
[Zensical](https://zensical.org/) (from the Material for MkDocs team), which
reads `mkdocs.yml` [directly](https://zensical.org/compatibility/). Building
the docs requires **Python 3.10+** (the runtime package still supports 3.8+).

## License

MIT License
