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