#! /usr/bin/env python3
import json
from dataclasses import field, dataclass
from http import HTTPStatus
from typing import Optional, List
from sanic import Sanic
from sanic.response import empty
from sanic_ext import validate
app = Sanic(name='name')
@dataclass
class SearchRequest:
names: Optional[List[str]] = field(default_factory=list)
# Proving that the dataclass is valid.
SearchRequest()
SearchRequest(names=['foo', 'bar'])
@app.post('/search')
@validate(json=SearchRequest)
def search(_, body: SearchRequest):
print(body.names)
return empty()
# This request succeeds with 204.
_, response = app.test_client.post('/search', content=json.dumps({'names': ['foo', 'bar']}))
assert response.status_code == HTTPStatus.NO_CONTENT, response.status
# This request fails with 400.
_, response = app.test_client.post('/search', content=json.dumps({}))
assert response.status_code == HTTPStatus.NO_CONTENT, response.status
[2022-01-13 09:19:30 -0700] [8488] [INFO]
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Sanic v21.12.1 │
│ Goin' Fast @ ('127.0.0.1', 50961) http://... │
├───────────────────────┬──────────────────────────────────────────────────────────────────────────┤
│ │ mode: production, single worker │
│ ▄███ █████ ██ │ server: sanic │
│ ██ │ python: 3.9.5 │
│ ▀███████ ███▄ │ platform: Linux-4.19.0-18-amd64-x86_64-with-glibc2.28 │
│ ██ │ packages: sanic-routing==0.7.2, sanic-testing==0.8.2, sanic-ext==21.12.1 │
│ ████ ████████▀ │ │
│ │ │
│ Build Fast. Run Fast. │ │
└───────────────────────┴──────────────────────────────────────────────────────────────────────────┘
[2022-01-13 09:19:30 -0700] [8488] [WARNING] Sanic is running in PRODUCTION mode. Consider using '--debug' or '--dev' while actively developing your application.
[2022-01-13 09:19:30 -0700] [8488] [INFO] Sanic Extensions:
[2022-01-13 09:19:30 -0700] [8488] [INFO] > http
[2022-01-13 09:19:30 -0700] [8488] [INFO] > openapi [http://('127.0.0.1', 50961) http://.../docs]
[2022-01-13 09:19:30 -0700] [8488] [INFO] > injection [0]
[2022-01-13 09:19:30 -0700] [8488] [INFO] http://127.0.0.1:50961/search
['foo', 'bar']
[2022-01-13 09:19:30 -0700] - (sanic.access)[INFO][127.0.0.1:59530]: POST http://127.0.0.1:50961/search 204 0
[2022-01-13 09:19:30 -0700] [8488] [INFO] Starting worker [8488]
[2022-01-13 09:19:30 -0700] [8488] [INFO] Stopping worker [8488]
[2022-01-13 09:19:30 -0700] [8488] [INFO] Server Stopped
[2022-01-13 09:19:30 -0700] [8488] [INFO]
┌──────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Sanic v21.12.1 │
│ Goin' Fast @ http://127.0.0.1:50961 │
├───────────────────────┬──────────────────────────────────────────────────────────────────────────┤
│ │ mode: production, single worker │
│ ▄███ █████ ██ │ server: sanic │
│ ██ │ python: 3.9.5 │
│ ▀███████ ███▄ │ platform: Linux-4.19.0-18-amd64-x86_64-with-glibc2.28 │
│ ██ │ packages: sanic-routing==0.7.2, sanic-testing==0.8.2, sanic-ext==21.12.1 │
│ ████ ████████▀ │ │
│ │ │
│ Build Fast. Run Fast. │ │
└───────────────────────┴──────────────────────────────────────────────────────────────────────────┘
[2022-01-13 09:19:30 -0700] [8488] [WARNING] Sanic is running in PRODUCTION mode. Consider using '--debug' or '--dev' while actively developing your application.
[2022-01-13 09:19:30 -0700] [8488] [INFO] Sanic Extensions:
[2022-01-13 09:19:30 -0700] [8488] [INFO] > http
[2022-01-13 09:19:30 -0700] [8488] [INFO] > openapi [http://127.0.0.1:50961/docs]
[2022-01-13 09:19:30 -0700] [8488] [INFO] > injection [0]
[2022-01-13 09:19:30 -0700] [8488] [INFO] http://127.0.0.1:50961/search
[2022-01-13 09:19:30 -0700] [8488] [ERROR] Exception occurred while handling uri: 'http://127.0.0.1:50961/search'
Traceback (most recent call last):
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 93, in check_data
hydration_values[key] = hint.validate(
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 46, in validate
_check_nullability(value, self.nullable, self.allowed, schema)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 120, in _check_nullability
allowed[0].validate(value, schema)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 58, in validate
value = _check_list(
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 145, in _check_list
raise ValueError(f"Value '{value}' must be a {hint}")
ValueError: Value '<factory>' must be a typing.List[str]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/validators.py", line 24, in validate_body
return validator(model, body)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/validators.py", line 36, in _validate_annotations
return check_data(model, body, schema, allow_multiple, allow_coerce)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/check.py", line 100, in check_data
raise TypeError(e)
TypeError: Value '<factory>' must be a typing.List[str]
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "handle_request", line 83, in handle_request
)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/decorator.py", line 37, in decorated_function
await do_validation(
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/setup.py", line 41, in do_validation
validation = validate_body(validator, model, data)
File "/home/user/projects/project/venv/lib/python3.9/site-packages/sanic_ext/extras/validation/validators.py", line 26, in validate_body
raise ValidationError(
sanic_ext.exceptions.ValidationError: Invalid request body: SearchRequest. Error: Value '<factory>' must be a typing.List[str]
[2022-01-13 09:19:30 -0700] - (sanic.access)[INFO][127.0.0.1:59532]: POST http://127.0.0.1:50961/search 400 796
[2022-01-13 09:19:30 -0700] [8488] [INFO] Starting worker [8488]
[2022-01-13 09:19:30 -0700] [8488] [INFO] Stopping worker [8488]
[2022-01-13 09:19:30 -0700] [8488] [INFO] Server Stopped
Traceback (most recent call last):
File "/home/user/.config/JetBrains/PyCharm2021.3/scratches/scratch_1.py", line 36, in <module>
assert response.status_code == HTTPStatus.NO_CONTENT, response.status
AssertionError: 400