Coverage for tests/test_extra_routes.py: 100%

64 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-08-08 03:53 +0000

1from typing import Optional 1abcde

2 

3from dirty_equals import IsDict 1abcde

4from fastapi import FastAPI 1abcde

5from fastapi.responses import JSONResponse 1abcde

6from fastapi.testclient import TestClient 1abcde

7from pydantic import BaseModel 1abcde

8 

9app = FastAPI() 1abcde

10 

11 

12class Item(BaseModel): 1abcde

13 name: str 1abcde

14 price: Optional[float] = None 1abcde

15 

16 

17@app.api_route("/items/{item_id}", methods=["GET"]) 1abcde

18def get_items(item_id: str): 1abcde

19 return {"item_id": item_id} 1abcde

20 

21 

22def get_not_decorated(item_id: str): 1abcde

23 return {"item_id": item_id} 1abcde

24 

25 

26app.add_api_route("/items-not-decorated/{item_id}", get_not_decorated) 1abcde

27 

28 

29@app.delete("/items/{item_id}") 1abcde

30def delete_item(item_id: str, item: Item): 1abcde

31 return {"item_id": item_id, "item": item} 1abcde

32 

33 

34@app.head("/items/{item_id}") 1abcde

35def head_item(item_id: str): 1abcde

36 return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) 1abcde

37 

38 

39@app.options("/items/{item_id}") 1abcde

40def options_item(item_id: str): 1abcde

41 return JSONResponse(None, headers={"x-fastapi-item-id": item_id}) 1abcde

42 

43 

44@app.patch("/items/{item_id}") 1abcde

45def patch_item(item_id: str, item: Item): 1abcde

46 return {"item_id": item_id, "item": item} 1abcde

47 

48 

49@app.trace("/items/{item_id}") 1abcde

50def trace_item(item_id: str): 1abcde

51 return JSONResponse(None, media_type="message/http") 1abcde

52 

53 

54client = TestClient(app) 1abcde

55 

56 

57def test_get_api_route(): 1abcde

58 response = client.get("/items/foo") 1abcde

59 assert response.status_code == 200, response.text 1abcde

60 assert response.json() == {"item_id": "foo"} 1abcde

61 

62 

63def test_get_api_route_not_decorated(): 1abcde

64 response = client.get("/items-not-decorated/foo") 1abcde

65 assert response.status_code == 200, response.text 1abcde

66 assert response.json() == {"item_id": "foo"} 1abcde

67 

68 

69def test_delete(): 1abcde

70 response = client.request("DELETE", "/items/foo", json={"name": "Foo"}) 1abcde

71 assert response.status_code == 200, response.text 1abcde

72 assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} 1abcde

73 

74 

75def test_head(): 1abcde

76 response = client.head("/items/foo") 1abcde

77 assert response.status_code == 200, response.text 1abcde

78 assert response.headers["x-fastapi-item-id"] == "foo" 1abcde

79 

80 

81def test_options(): 1abcde

82 response = client.options("/items/foo") 1abcde

83 assert response.status_code == 200, response.text 1abcde

84 assert response.headers["x-fastapi-item-id"] == "foo" 1abcde

85 

86 

87def test_patch(): 1abcde

88 response = client.patch("/items/foo", json={"name": "Foo"}) 1abcde

89 assert response.status_code == 200, response.text 1abcde

90 assert response.json() == {"item_id": "foo", "item": {"name": "Foo", "price": None}} 1abcde

91 

92 

93def test_trace(): 1abcde

94 response = client.request("trace", "/items/foo") 1abcde

95 assert response.status_code == 200, response.text 1abcde

96 assert response.headers["content-type"] == "message/http" 1abcde

97 

98 

99def test_openapi_schema(): 1abcde

100 response = client.get("/openapi.json") 1abcde

101 assert response.status_code == 200, response.text 1abcde

102 assert response.json() == { 1abcde

103 "openapi": "3.1.0", 

104 "info": {"title": "FastAPI", "version": "0.1.0"}, 

105 "paths": { 

106 "/items/{item_id}": { 

107 "get": { 

108 "responses": { 

109 "200": { 

110 "description": "Successful Response", 

111 "content": {"application/json": {"schema": {}}}, 

112 }, 

113 "422": { 

114 "description": "Validation Error", 

115 "content": { 

116 "application/json": { 

117 "schema": { 

118 "$ref": "#/components/schemas/HTTPValidationError" 

119 } 

120 } 

121 }, 

122 }, 

123 }, 

124 "summary": "Get Items", 

125 "operationId": "get_items_items__item_id__get", 

126 "parameters": [ 

127 { 

128 "required": True, 

129 "schema": {"title": "Item Id", "type": "string"}, 

130 "name": "item_id", 

131 "in": "path", 

132 } 

133 ], 

134 }, 

135 "delete": { 

136 "responses": { 

137 "200": { 

138 "description": "Successful Response", 

139 "content": {"application/json": {"schema": {}}}, 

140 }, 

141 "422": { 

142 "description": "Validation Error", 

143 "content": { 

144 "application/json": { 

145 "schema": { 

146 "$ref": "#/components/schemas/HTTPValidationError" 

147 } 

148 } 

149 }, 

150 }, 

151 }, 

152 "summary": "Delete Item", 

153 "operationId": "delete_item_items__item_id__delete", 

154 "parameters": [ 

155 { 

156 "required": True, 

157 "schema": {"title": "Item Id", "type": "string"}, 

158 "name": "item_id", 

159 "in": "path", 

160 } 

161 ], 

162 "requestBody": { 

163 "content": { 

164 "application/json": { 

165 "schema": {"$ref": "#/components/schemas/Item"} 

166 } 

167 }, 

168 "required": True, 

169 }, 

170 }, 

171 "options": { 

172 "responses": { 

173 "200": { 

174 "description": "Successful Response", 

175 "content": {"application/json": {"schema": {}}}, 

176 }, 

177 "422": { 

178 "description": "Validation Error", 

179 "content": { 

180 "application/json": { 

181 "schema": { 

182 "$ref": "#/components/schemas/HTTPValidationError" 

183 } 

184 } 

185 }, 

186 }, 

187 }, 

188 "summary": "Options Item", 

189 "operationId": "options_item_items__item_id__options", 

190 "parameters": [ 

191 { 

192 "required": True, 

193 "schema": {"title": "Item Id", "type": "string"}, 

194 "name": "item_id", 

195 "in": "path", 

196 } 

197 ], 

198 }, 

199 "head": { 

200 "responses": { 

201 "200": { 

202 "description": "Successful Response", 

203 "content": {"application/json": {"schema": {}}}, 

204 }, 

205 "422": { 

206 "description": "Validation Error", 

207 "content": { 

208 "application/json": { 

209 "schema": { 

210 "$ref": "#/components/schemas/HTTPValidationError" 

211 } 

212 } 

213 }, 

214 }, 

215 }, 

216 "summary": "Head Item", 

217 "operationId": "head_item_items__item_id__head", 

218 "parameters": [ 

219 { 

220 "required": True, 

221 "schema": {"title": "Item Id", "type": "string"}, 

222 "name": "item_id", 

223 "in": "path", 

224 } 

225 ], 

226 }, 

227 "patch": { 

228 "responses": { 

229 "200": { 

230 "description": "Successful Response", 

231 "content": {"application/json": {"schema": {}}}, 

232 }, 

233 "422": { 

234 "description": "Validation Error", 

235 "content": { 

236 "application/json": { 

237 "schema": { 

238 "$ref": "#/components/schemas/HTTPValidationError" 

239 } 

240 } 

241 }, 

242 }, 

243 }, 

244 "summary": "Patch Item", 

245 "operationId": "patch_item_items__item_id__patch", 

246 "parameters": [ 

247 { 

248 "required": True, 

249 "schema": {"title": "Item Id", "type": "string"}, 

250 "name": "item_id", 

251 "in": "path", 

252 } 

253 ], 

254 "requestBody": { 

255 "content": { 

256 "application/json": { 

257 "schema": {"$ref": "#/components/schemas/Item"} 

258 } 

259 }, 

260 "required": True, 

261 }, 

262 }, 

263 "trace": { 

264 "responses": { 

265 "200": { 

266 "description": "Successful Response", 

267 "content": {"application/json": {"schema": {}}}, 

268 }, 

269 "422": { 

270 "description": "Validation Error", 

271 "content": { 

272 "application/json": { 

273 "schema": { 

274 "$ref": "#/components/schemas/HTTPValidationError" 

275 } 

276 } 

277 }, 

278 }, 

279 }, 

280 "summary": "Trace Item", 

281 "operationId": "trace_item_items__item_id__trace", 

282 "parameters": [ 

283 { 

284 "required": True, 

285 "schema": {"title": "Item Id", "type": "string"}, 

286 "name": "item_id", 

287 "in": "path", 

288 } 

289 ], 

290 }, 

291 }, 

292 "/items-not-decorated/{item_id}": { 

293 "get": { 

294 "responses": { 

295 "200": { 

296 "description": "Successful Response", 

297 "content": {"application/json": {"schema": {}}}, 

298 }, 

299 "422": { 

300 "description": "Validation Error", 

301 "content": { 

302 "application/json": { 

303 "schema": { 

304 "$ref": "#/components/schemas/HTTPValidationError" 

305 } 

306 } 

307 }, 

308 }, 

309 }, 

310 "summary": "Get Not Decorated", 

311 "operationId": "get_not_decorated_items_not_decorated__item_id__get", 

312 "parameters": [ 

313 { 

314 "required": True, 

315 "schema": {"title": "Item Id", "type": "string"}, 

316 "name": "item_id", 

317 "in": "path", 

318 } 

319 ], 

320 } 

321 }, 

322 }, 

323 "components": { 

324 "schemas": { 

325 "Item": { 

326 "title": "Item", 

327 "required": ["name"], 

328 "type": "object", 

329 "properties": { 

330 "name": {"title": "Name", "type": "string"}, 

331 "price": IsDict( 

332 { 

333 "title": "Price", 

334 "anyOf": [{"type": "number"}, {"type": "null"}], 

335 } 

336 ) 

337 # TODO: remove when deprecating Pydantic v1 

338 | IsDict({"title": "Price", "type": "number"}), 

339 }, 

340 }, 

341 "ValidationError": { 

342 "title": "ValidationError", 

343 "required": ["loc", "msg", "type"], 

344 "type": "object", 

345 "properties": { 

346 "loc": { 

347 "title": "Location", 

348 "type": "array", 

349 "items": { 

350 "anyOf": [{"type": "string"}, {"type": "integer"}] 

351 }, 

352 }, 

353 "msg": {"title": "Message", "type": "string"}, 

354 "type": {"title": "Error Type", "type": "string"}, 

355 }, 

356 }, 

357 "HTTPValidationError": { 

358 "title": "HTTPValidationError", 

359 "type": "object", 

360 "properties": { 

361 "detail": { 

362 "title": "Detail", 

363 "type": "array", 

364 "items": {"$ref": "#/components/schemas/ValidationError"}, 

365 } 

366 }, 

367 }, 

368 } 

369 }, 

370 }