mirror of
https://github.com/fastapi/fastapi.git
synced 2026-04-13 11:33:45 -04:00
✨ Add parameter dependencies to path operation decorators and include_router (#235)
* ✨ Implement dependencies in decorator and .include_router * 📝 Add docs for parameter dependencies * ✅ Add tests for dependencies parameter * 🔥 Remove debugging prints in tests * 📝 Update release notes
This commit is contained in:
committed by
GitHub
parent
7c50025c47
commit
e92b43b5c8
@@ -74,10 +74,28 @@ openapi_schema = {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"tags": ["items"],
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"parameters": [
|
||||
{
|
||||
"required": True,
|
||||
"schema": {"title": "X-Token", "type": "string"},
|
||||
"name": "x-token",
|
||||
"in": "header",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
"/items/{item_id}": {
|
||||
@@ -108,7 +126,13 @@ openapi_schema = {
|
||||
"schema": {"title": "Item_Id", "type": "string"},
|
||||
"name": "item_id",
|
||||
"in": "path",
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": True,
|
||||
"schema": {"title": "X-Token", "type": "string"},
|
||||
"name": "x-token",
|
||||
"in": "header",
|
||||
},
|
||||
],
|
||||
},
|
||||
"put": {
|
||||
@@ -139,7 +163,13 @@ openapi_schema = {
|
||||
"schema": {"title": "Item_Id", "type": "string"},
|
||||
"name": "item_id",
|
||||
"in": "path",
|
||||
}
|
||||
},
|
||||
{
|
||||
"required": True,
|
||||
"schema": {"title": "X-Token", "type": "string"},
|
||||
"name": "x-token",
|
||||
"in": "header",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
@@ -177,29 +207,94 @@ openapi_schema = {
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"path,expected_status,expected_response",
|
||||
"path,expected_status,expected_response,headers",
|
||||
[
|
||||
("/users", 200, [{"username": "Foo"}, {"username": "Bar"}]),
|
||||
("/users/foo", 200, {"username": "foo"}),
|
||||
("/users/me", 200, {"username": "fakecurrentuser"}),
|
||||
("/items", 200, [{"name": "Item Foo"}, {"name": "item Bar"}]),
|
||||
("/items/bar", 200, {"name": "Fake Specific Item", "item_id": "bar"}),
|
||||
("/openapi.json", 200, openapi_schema),
|
||||
("/users", 200, [{"username": "Foo"}, {"username": "Bar"}], {}),
|
||||
("/users/foo", 200, {"username": "foo"}, {}),
|
||||
("/users/me", 200, {"username": "fakecurrentuser"}, {}),
|
||||
(
|
||||
"/items",
|
||||
200,
|
||||
[{"name": "Item Foo"}, {"name": "item Bar"}],
|
||||
{"X-Token": "fake-super-secret-token"},
|
||||
),
|
||||
(
|
||||
"/items/bar",
|
||||
200,
|
||||
{"name": "Fake Specific Item", "item_id": "bar"},
|
||||
{"X-Token": "fake-super-secret-token"},
|
||||
),
|
||||
("/items", 400, {"detail": "X-Token header invalid"}, {"X-Token": "invalid"}),
|
||||
(
|
||||
"/items/bar",
|
||||
400,
|
||||
{"detail": "X-Token header invalid"},
|
||||
{"X-Token": "invalid"},
|
||||
),
|
||||
(
|
||||
"/items",
|
||||
422,
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["header", "x-token"],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing",
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
),
|
||||
(
|
||||
"/items/bar",
|
||||
422,
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["header", "x-token"],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing",
|
||||
}
|
||||
]
|
||||
},
|
||||
{},
|
||||
),
|
||||
("/openapi.json", 200, openapi_schema, {}),
|
||||
],
|
||||
)
|
||||
def test_get_path(path, expected_status, expected_response):
|
||||
response = client.get(path)
|
||||
def test_get_path(path, expected_status, expected_response, headers):
|
||||
response = client.get(path, headers=headers)
|
||||
assert response.status_code == expected_status
|
||||
assert response.json() == expected_response
|
||||
|
||||
|
||||
def test_put():
|
||||
def test_put_no_header():
|
||||
response = client.put("/items/foo")
|
||||
assert response.status_code == 422
|
||||
assert response.json() == {
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["header", "x-token"],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def test_put_invalid_header():
|
||||
response = client.put("/items/foo", headers={"X-Token": "invalid"})
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"detail": "X-Token header invalid"}
|
||||
|
||||
|
||||
def test_put():
|
||||
response = client.put("/items/foo", headers={"X-Token": "fake-super-secret-token"})
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {"item_id": "foo", "name": "The Fighters"}
|
||||
|
||||
|
||||
def test_put_forbidden():
|
||||
response = client.put("/items/bar")
|
||||
response = client.put("/items/bar", headers={"X-Token": "fake-super-secret-token"})
|
||||
assert response.status_code == 403
|
||||
assert response.json() == {"detail": "You can only update the item: foo"}
|
||||
|
||||
128
tests/test_tutorial/test_dependencies/test_tutorial006.py
Normal file
128
tests/test_tutorial/test_dependencies/test_tutorial006.py
Normal file
@@ -0,0 +1,128 @@
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from dependencies.tutorial006 import app
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
openapi_schema = {
|
||||
"openapi": "3.0.2",
|
||||
"info": {"title": "Fast API", "version": "0.1.0"},
|
||||
"paths": {
|
||||
"/items/": {
|
||||
"get": {
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Successful Response",
|
||||
"content": {"application/json": {"schema": {}}},
|
||||
},
|
||||
"422": {
|
||||
"description": "Validation Error",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/HTTPValidationError"
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
"summary": "Read Items",
|
||||
"operationId": "read_items_items__get",
|
||||
"parameters": [
|
||||
{
|
||||
"required": True,
|
||||
"schema": {"title": "X-Token", "type": "string"},
|
||||
"name": "x-token",
|
||||
"in": "header",
|
||||
},
|
||||
{
|
||||
"required": True,
|
||||
"schema": {"title": "X-Key", "type": "string"},
|
||||
"name": "x-key",
|
||||
"in": "header",
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"schemas": {
|
||||
"ValidationError": {
|
||||
"title": "ValidationError",
|
||||
"required": ["loc", "msg", "type"],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"loc": {
|
||||
"title": "Location",
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
},
|
||||
"msg": {"title": "Message", "type": "string"},
|
||||
"type": {"title": "Error Type", "type": "string"},
|
||||
},
|
||||
},
|
||||
"HTTPValidationError": {
|
||||
"title": "HTTPValidationError",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"detail": {
|
||||
"title": "Detail",
|
||||
"type": "array",
|
||||
"items": {"$ref": "#/components/schemas/ValidationError"},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_openapi_schema():
|
||||
response = client.get("/openapi.json")
|
||||
assert response.status_code == 200
|
||||
assert response.json() == openapi_schema
|
||||
|
||||
|
||||
def test_get_no_headers():
|
||||
response = client.get("/items/")
|
||||
assert response.status_code == 422
|
||||
assert response.json() == {
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["header", "x-token"],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing",
|
||||
},
|
||||
{
|
||||
"loc": ["header", "x-key"],
|
||||
"msg": "field required",
|
||||
"type": "value_error.missing",
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
def test_get_invalid_one_header():
|
||||
response = client.get("/items/", headers={"X-Token": "invalid"})
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"detail": "X-Token header invalid"}
|
||||
|
||||
|
||||
def test_get_invalid_second_header():
|
||||
response = client.get(
|
||||
"/items/", headers={"X-Token": "fake-super-secret-token", "X-Key": "invalid"}
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"detail": "X-Key header invalid"}
|
||||
|
||||
|
||||
def test_get_valid_headers():
|
||||
response = client.get(
|
||||
"/items/",
|
||||
headers={
|
||||
"X-Token": "fake-super-secret-token",
|
||||
"X-Key": "fake-super-secret-key",
|
||||
},
|
||||
)
|
||||
assert response.status_code == 200
|
||||
assert response.json() == [{"item": "Foo"}, {"item": "Bar"}]
|
||||
@@ -166,8 +166,6 @@ def test_post_form_no_body():
|
||||
|
||||
def test_post_body_json():
|
||||
response = client.post("/files/", json={"file": "Foo"})
|
||||
print(response)
|
||||
print(response.content)
|
||||
assert response.status_code == 422
|
||||
assert response.json() == file_required
|
||||
|
||||
|
||||
@@ -227,7 +227,6 @@ def test_token():
|
||||
response = client.get(
|
||||
"/users/me", headers={"Authorization": f"Bearer {access_token}"}
|
||||
)
|
||||
print(response.json())
|
||||
assert response.status_code == 200
|
||||
assert response.json() == {
|
||||
"username": "johndoe",
|
||||
@@ -319,7 +318,6 @@ def test_token_inactive_user():
|
||||
response = client.get(
|
||||
"/users/me", headers={"Authorization": f"Bearer {access_token}"}
|
||||
)
|
||||
print(response.json())
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"detail": "Inactive user"}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user