1from typing import List
2
3from fastapi import FastAPI
4from fastapi.testclient import TestClient
5from pydantic import BaseModel, Field
6
7app = FastAPI()
8
9
10class Model(BaseModel):
11    name: str = Field(alias="alias")
12
13
14class ModelNoAlias(BaseModel):
15    name: str
16
17    class Config:
18        schema_extra = {
19            "description": (
20                "response_model_by_alias=False is basically a quick hack, to support "
21                "proper OpenAPI use another model with the correct field names"
22            )
23        }
24
25
26@app.get("/dict", response_model=Model, response_model_by_alias=False)
27def read_dict():
28    return {"alias": "Foo"}
29
30
31@app.get("/model", response_model=Model, response_model_by_alias=False)
32def read_model():
33    return Model(alias="Foo")
34
35
36@app.get("/list", response_model=List[Model], response_model_by_alias=False)
37def read_list():
38    return [{"alias": "Foo"}, {"alias": "Bar"}]
39
40
41@app.get("/by-alias/dict", response_model=Model)
42def by_alias_dict():
43    return {"alias": "Foo"}
44
45
46@app.get("/by-alias/model", response_model=Model)
47def by_alias_model():
48    return Model(alias="Foo")
49
50
51@app.get("/by-alias/list", response_model=List[Model])
52def by_alias_list():
53    return [{"alias": "Foo"}, {"alias": "Bar"}]
54
55
56@app.get("/no-alias/dict", response_model=ModelNoAlias)
57def no_alias_dict():
58    return {"name": "Foo"}
59
60
61@app.get("/no-alias/model", response_model=ModelNoAlias)
62def no_alias_model():
63    return ModelNoAlias(name="Foo")
64
65
66@app.get("/no-alias/list", response_model=List[ModelNoAlias])
67def no_alias_list():
68    return [{"name": "Foo"}, {"name": "Bar"}]
69
70
71openapi_schema = {
72    "openapi": "3.0.2",
73    "info": {"title": "FastAPI", "version": "0.1.0"},
74    "paths": {
75        "/dict": {
76            "get": {
77                "summary": "Read Dict",
78                "operationId": "read_dict_dict_get",
79                "responses": {
80                    "200": {
81                        "description": "Successful Response",
82                        "content": {
83                            "application/json": {
84                                "schema": {"$ref": "#/components/schemas/Model"}
85                            }
86                        },
87                    }
88                },
89            }
90        },
91        "/model": {
92            "get": {
93                "summary": "Read Model",
94                "operationId": "read_model_model_get",
95                "responses": {
96                    "200": {
97                        "description": "Successful Response",
98                        "content": {
99                            "application/json": {
100                                "schema": {"$ref": "#/components/schemas/Model"}
101                            }
102                        },
103                    }
104                },
105            }
106        },
107        "/list": {
108            "get": {
109                "summary": "Read List",
110                "operationId": "read_list_list_get",
111                "responses": {
112                    "200": {
113                        "description": "Successful Response",
114                        "content": {
115                            "application/json": {
116                                "schema": {
117                                    "title": "Response Read List List Get",
118                                    "type": "array",
119                                    "items": {"$ref": "#/components/schemas/Model"},
120                                }
121                            }
122                        },
123                    }
124                },
125            }
126        },
127        "/by-alias/dict": {
128            "get": {
129                "summary": "By Alias Dict",
130                "operationId": "by_alias_dict_by_alias_dict_get",
131                "responses": {
132                    "200": {
133                        "description": "Successful Response",
134                        "content": {
135                            "application/json": {
136                                "schema": {"$ref": "#/components/schemas/Model"}
137                            }
138                        },
139                    }
140                },
141            }
142        },
143        "/by-alias/model": {
144            "get": {
145                "summary": "By Alias Model",
146                "operationId": "by_alias_model_by_alias_model_get",
147                "responses": {
148                    "200": {
149                        "description": "Successful Response",
150                        "content": {
151                            "application/json": {
152                                "schema": {"$ref": "#/components/schemas/Model"}
153                            }
154                        },
155                    }
156                },
157            }
158        },
159        "/by-alias/list": {
160            "get": {
161                "summary": "By Alias List",
162                "operationId": "by_alias_list_by_alias_list_get",
163                "responses": {
164                    "200": {
165                        "description": "Successful Response",
166                        "content": {
167                            "application/json": {
168                                "schema": {
169                                    "title": "Response By Alias List By Alias List Get",
170                                    "type": "array",
171                                    "items": {"$ref": "#/components/schemas/Model"},
172                                }
173                            }
174                        },
175                    }
176                },
177            }
178        },
179        "/no-alias/dict": {
180            "get": {
181                "summary": "No Alias Dict",
182                "operationId": "no_alias_dict_no_alias_dict_get",
183                "responses": {
184                    "200": {
185                        "description": "Successful Response",
186                        "content": {
187                            "application/json": {
188                                "schema": {"$ref": "#/components/schemas/ModelNoAlias"}
189                            }
190                        },
191                    }
192                },
193            }
194        },
195        "/no-alias/model": {
196            "get": {
197                "summary": "No Alias Model",
198                "operationId": "no_alias_model_no_alias_model_get",
199                "responses": {
200                    "200": {
201                        "description": "Successful Response",
202                        "content": {
203                            "application/json": {
204                                "schema": {"$ref": "#/components/schemas/ModelNoAlias"}
205                            }
206                        },
207                    }
208                },
209            }
210        },
211        "/no-alias/list": {
212            "get": {
213                "summary": "No Alias List",
214                "operationId": "no_alias_list_no_alias_list_get",
215                "responses": {
216                    "200": {
217                        "description": "Successful Response",
218                        "content": {
219                            "application/json": {
220                                "schema": {
221                                    "title": "Response No Alias List No Alias List Get",
222                                    "type": "array",
223                                    "items": {
224                                        "$ref": "#/components/schemas/ModelNoAlias"
225                                    },
226                                }
227                            }
228                        },
229                    }
230                },
231            }
232        },
233    },
234    "components": {
235        "schemas": {
236            "Model": {
237                "title": "Model",
238                "required": ["alias"],
239                "type": "object",
240                "properties": {"alias": {"title": "Alias", "type": "string"}},
241            },
242            "ModelNoAlias": {
243                "title": "ModelNoAlias",
244                "required": ["name"],
245                "type": "object",
246                "properties": {"name": {"title": "Name", "type": "string"}},
247                "description": "response_model_by_alias=False is basically a quick hack, to support proper OpenAPI use another model with the correct field names",
248            },
249        }
250    },
251}
252
253
254client = TestClient(app)
255
256
257def test_openapi_schema():
258    response = client.get("/openapi.json")
259    assert response.status_code == 200, response.text
260    assert response.json() == openapi_schema
261
262
263def test_read_dict():
264    response = client.get("/dict")
265    assert response.status_code == 200, response.text
266    assert response.json() == {"name": "Foo"}
267
268
269def test_read_model():
270    response = client.get("/model")
271    assert response.status_code == 200, response.text
272    assert response.json() == {"name": "Foo"}
273
274
275def test_read_list():
276    response = client.get("/list")
277    assert response.status_code == 200, response.text
278    assert response.json() == [
279        {"name": "Foo"},
280        {"name": "Bar"},
281    ]
282
283
284def test_read_dict_by_alias():
285    response = client.get("/by-alias/dict")
286    assert response.status_code == 200, response.text
287    assert response.json() == {"alias": "Foo"}
288
289
290def test_read_model_by_alias():
291    response = client.get("/by-alias/model")
292    assert response.status_code == 200, response.text
293    assert response.json() == {"alias": "Foo"}
294
295
296def test_read_list_by_alias():
297    response = client.get("/by-alias/list")
298    assert response.status_code == 200, response.text
299    assert response.json() == [
300        {"alias": "Foo"},
301        {"alias": "Bar"},
302    ]
303
304
305def test_read_dict_no_alias():
306    response = client.get("/no-alias/dict")
307    assert response.status_code == 200, response.text
308    assert response.json() == {"name": "Foo"}
309
310
311def test_read_model_no_alias():
312    response = client.get("/no-alias/model")
313    assert response.status_code == 200, response.text
314    assert response.json() == {"name": "Foo"}
315
316
317def test_read_list_no_alias():
318    response = client.get("/no-alias/list")
319    assert response.status_code == 200, response.text
320    assert response.json() == [
321        {"name": "Foo"},
322        {"name": "Bar"},
323    ]
324