Browse Source

🔒 Fix constraining return values to model

pull/11/head
Sebastián Ramírez 7 years ago
parent
commit
da166b7967
  1. 2
      fastapi/__init__.py
  2. 15
      fastapi/routing.py
  3. 34
      tests/main.py
  4. 100
      tests/test_path.py

2
fastapi/__init__.py

@ -1,6 +1,6 @@
"""FastAPI framework, high performance, easy to learn, fast to code, ready for production""" """FastAPI framework, high performance, easy to learn, fast to code, ready for production"""
__version__ = "0.1.2" __version__ = "0.1.3"
from .applications import FastAPI from .applications import FastAPI
from .routing import APIRouter from .routing import APIRouter

15
fastapi/routing.py

@ -1,5 +1,6 @@
import asyncio import asyncio
import inspect import inspect
import logging
from typing import Any, Callable, List, Optional, Type from typing import Any, Callable, List, Optional, Type
from fastapi import params from fastapi import params
@ -47,6 +48,7 @@ def get_app(
is_body_form = body_field and isinstance(body_field.schema, params.Form) is_body_form = body_field and isinstance(body_field.schema, params.Form)
async def app(request: Request) -> Response: async def app(request: Request) -> Response:
try:
body = None body = None
if body_field: if body_field:
if is_body_form: if is_body_form:
@ -59,9 +61,17 @@ def get_app(
body[field] = value body[field] = value
else: else:
body = await request.json() body = await request.json()
except Exception:
raise HTTPException(
status_code=400, detail="There was an error parsing the body"
)
try:
values, errors = await solve_dependencies( values, errors = await solve_dependencies(
request=request, dependant=dependant, body=body request=request, dependant=dependant, body=body
) )
except Exception as e:
logging.error("Error solving dependencies", e)
raise HTTPException(status_code=400, detail="Error processing request")
if errors: if errors:
errors_out = ValidationError(errors) errors_out = ValidationError(errors)
raise HTTPException( raise HTTPException(
@ -77,7 +87,10 @@ def get_app(
return raw_response return raw_response
if isinstance(raw_response, BaseModel): if isinstance(raw_response, BaseModel):
return content_type( return content_type(
content=jsonable_encoder(raw_response), status_code=status_code content=serialize_response(
field=response_field, response=raw_response
),
status_code=status_code,
) )
errors = [] errors = []
try: try:

34
tests/main.py

@ -67,87 +67,87 @@ def get_path_param_required_id(item_id: str = Path(...)):
@app.get("/path/param-minlength/{item_id}") @app.get("/path/param-minlength/{item_id}")
def get_path_param_min_length(item_id: str = Path(..., min_length = 3)): def get_path_param_min_length(item_id: str = Path(..., min_length=3)):
return item_id return item_id
@app.get("/path/param-maxlength/{item_id}") @app.get("/path/param-maxlength/{item_id}")
def get_path_param_max_length(item_id: str = Path(..., max_length = 3)): def get_path_param_max_length(item_id: str = Path(..., max_length=3)):
return item_id return item_id
@app.get("/path/param-min_maxlength/{item_id}") @app.get("/path/param-min_maxlength/{item_id}")
def get_path_param_min_max_length(item_id: str = Path(..., max_length = 3, min_length = 2)): def get_path_param_min_max_length(item_id: str = Path(..., max_length=3, min_length=2)):
return item_id return item_id
@app.get("/path/param-gt/{item_id}") @app.get("/path/param-gt/{item_id}")
def get_path_param_gt(item_id: float = Path(..., gt = 3)): def get_path_param_gt(item_id: float = Path(..., gt=3)):
return item_id return item_id
@app.get("/path/param-gt0/{item_id}") @app.get("/path/param-gt0/{item_id}")
def get_path_param_gt0(item_id: float = Path(..., gt = 0)): def get_path_param_gt0(item_id: float = Path(..., gt=0)):
return item_id return item_id
@app.get("/path/param-ge/{item_id}") @app.get("/path/param-ge/{item_id}")
def get_path_param_ge(item_id: float = Path(..., ge = 3)): def get_path_param_ge(item_id: float = Path(..., ge=3)):
return item_id return item_id
@app.get("/path/param-lt/{item_id}") @app.get("/path/param-lt/{item_id}")
def get_path_param_lt(item_id: float = Path(..., lt = 3)): def get_path_param_lt(item_id: float = Path(..., lt=3)):
return item_id return item_id
@app.get("/path/param-lt0/{item_id}") @app.get("/path/param-lt0/{item_id}")
def get_path_param_lt0(item_id: float = Path(..., lt = 0)): def get_path_param_lt0(item_id: float = Path(..., lt=0)):
return item_id return item_id
@app.get("/path/param-le/{item_id}") @app.get("/path/param-le/{item_id}")
def get_path_param_le(item_id: float = Path(..., le = 3)): def get_path_param_le(item_id: float = Path(..., le=3)):
return item_id return item_id
@app.get("/path/param-lt-gt/{item_id}") @app.get("/path/param-lt-gt/{item_id}")
def get_path_param_lt_gt(item_id: float = Path(..., lt = 3, gt = 1)): def get_path_param_lt_gt(item_id: float = Path(..., lt=3, gt=1)):
return item_id return item_id
@app.get("/path/param-le-ge/{item_id}") @app.get("/path/param-le-ge/{item_id}")
def get_path_param_le_ge(item_id: float = Path(..., le = 3, ge = 1)): def get_path_param_le_ge(item_id: float = Path(..., le=3, ge=1)):
return item_id return item_id
@app.get("/path/param-lt-int/{item_id}") @app.get("/path/param-lt-int/{item_id}")
def get_path_param_lt_int(item_id: int = Path(..., lt = 3)): def get_path_param_lt_int(item_id: int = Path(..., lt=3)):
return item_id return item_id
@app.get("/path/param-gt-int/{item_id}") @app.get("/path/param-gt-int/{item_id}")
def get_path_param_gt_int(item_id: int = Path(..., gt = 3)): def get_path_param_gt_int(item_id: int = Path(..., gt=3)):
return item_id return item_id
@app.get("/path/param-le-int/{item_id}") @app.get("/path/param-le-int/{item_id}")
def get_path_param_le_int(item_id: int = Path(..., le = 3)): def get_path_param_le_int(item_id: int = Path(..., le=3)):
return item_id return item_id
@app.get("/path/param-ge-int/{item_id}") @app.get("/path/param-ge-int/{item_id}")
def get_path_param_ge_int(item_id: int = Path(..., ge = 3)): def get_path_param_ge_int(item_id: int = Path(..., ge=3)):
return item_id return item_id
@app.get("/path/param-lt-gt-int/{item_id}") @app.get("/path/param-lt-gt-int/{item_id}")
def get_path_param_lt_gt_int(item_id: int = Path(..., lt = 3, gt = 1)): def get_path_param_lt_gt_int(item_id: int = Path(..., lt=3, gt=1)):
return item_id return item_id
@app.get("/path/param-le-ge-int/{item_id}") @app.get("/path/param-le-ge-int/{item_id}")
def get_path_param_le_ge_int(item_id: int = Path(..., le = 3, ge = 1)): def get_path_param_le_ge_int(item_id: int = Path(..., le=3, ge=1)):
return item_id return item_id

100
tests/test_path.py

@ -38,27 +38,49 @@ response_not_valid_float = {
] ]
} }
response_at_least_3 = {"detail":[{"loc":["path","item_id"],"msg":"ensure this value has at least 3 characters","type":"value_error.any_str.min_length","ctx":{"limit_value":3}}]} response_at_least_3 = {
"detail": [
{
"loc": ["path", "item_id"],
"msg": "ensure this value has at least 3 characters",
"type": "value_error.any_str.min_length",
"ctx": {"limit_value": 3},
}
]
}
response_at_least_2 = {"detail":[{"loc":["path","item_id"],"msg":"ensure this value has at least 2 characters","type":"value_error.any_str.min_length","ctx":{"limit_value":2}}]} response_at_least_2 = {
"detail": [
{
"loc": ["path", "item_id"],
"msg": "ensure this value has at least 2 characters",
"type": "value_error.any_str.min_length",
"ctx": {"limit_value": 2},
}
]
}
response_maximum_3 = {"detail":[{"loc":["path","item_id"],"msg":"ensure this value has at most 3 characters","type":"value_error.any_str.max_length","ctx":{"limit_value":3}}]} response_maximum_3 = {
"detail": [
{
"loc": ["path", "item_id"],
"msg": "ensure this value has at most 3 characters",
"type": "value_error.any_str.max_length",
"ctx": {"limit_value": 3},
}
]
}
response_greater_than_3 = { response_greater_than_3 = {
"detail": [ "detail": [
{ {
"loc": [ "loc": ["path", "item_id"],
"path",
"item_id"
],
"msg": "ensure this value is greater than 3", "msg": "ensure this value is greater than 3",
"type": "value_error.number.not_gt", "type": "value_error.number.not_gt",
"ctx": { "ctx": {"limit_value": 3},
"limit_value": 3
}
} }
] ]
} }
@ -67,15 +89,10 @@ response_greater_than_3 = {
response_greater_than_0 = { response_greater_than_0 = {
"detail": [ "detail": [
{ {
"loc": [ "loc": ["path", "item_id"],
"path",
"item_id"
],
"msg": "ensure this value is greater than 0", "msg": "ensure this value is greater than 0",
"type": "value_error.number.not_gt", "type": "value_error.number.not_gt",
"ctx": { "ctx": {"limit_value": 0},
"limit_value": 0
}
} }
] ]
} }
@ -84,35 +101,34 @@ response_greater_than_0 = {
response_greater_than_1 = { response_greater_than_1 = {
"detail": [ "detail": [
{ {
"loc": [ "loc": ["path", "item_id"],
"path",
"item_id"
],
"msg": "ensure this value is greater than 1", "msg": "ensure this value is greater than 1",
"type": "value_error.number.not_gt", "type": "value_error.number.not_gt",
"ctx": { "ctx": {"limit_value": 1},
"limit_value": 1
}
} }
] ]
} }
response_greater_than_equal_3 = {"detail":[{"loc":["path","item_id"],"msg":"ensure this value is greater than or equal to 3","type":"value_error.number.not_ge","ctx":{"limit_value":3}}]} response_greater_than_equal_3 = {
"detail": [
{
"loc": ["path", "item_id"],
"msg": "ensure this value is greater than or equal to 3",
"type": "value_error.number.not_ge",
"ctx": {"limit_value": 3},
}
]
}
response_less_than_3 = { response_less_than_3 = {
"detail": [ "detail": [
{ {
"loc": [ "loc": ["path", "item_id"],
"path",
"item_id"
],
"msg": "ensure this value is less than 3", "msg": "ensure this value is less than 3",
"type": "value_error.number.not_lt", "type": "value_error.number.not_lt",
"ctx": { "ctx": {"limit_value": 3},
"limit_value": 3
}
} }
] ]
} }
@ -121,21 +137,25 @@ response_less_than_3 = {
response_less_than_0 = { response_less_than_0 = {
"detail": [ "detail": [
{ {
"loc": [ "loc": ["path", "item_id"],
"path",
"item_id"
],
"msg": "ensure this value is less than 0", "msg": "ensure this value is less than 0",
"type": "value_error.number.not_lt", "type": "value_error.number.not_lt",
"ctx": { "ctx": {"limit_value": 0},
"limit_value": 0
}
} }
] ]
} }
response_less_than_equal_3 = {"detail":[{"loc":["path","item_id"],"msg":"ensure this value is less than or equal to 3","type":"value_error.number.not_le","ctx":{"limit_value":3}}]} response_less_than_equal_3 = {
"detail": [
{
"loc": ["path", "item_id"],
"msg": "ensure this value is less than or equal to 3",
"type": "value_error.number.not_le",
"ctx": {"limit_value": 3},
}
]
}
@pytest.mark.parametrize( @pytest.mark.parametrize(

Loading…
Cancel
Save