Adding Swagger Docs endpoint & API Test Script

هذا الالتزام موجود في:
ahmedgamalyousef
2025-09-30 23:23:53 +03:00
الأصل 00d4b0a5ff
التزام 12ebec097c
5 ملفات معدلة مع 960 إضافات و66 حذوفات

عرض الملف

@@ -127,3 +127,208 @@
2025-09-29 19:55:02,233 [INFO] REQUEST: method=GET path=/fruits args={} body=None ip=127.0.0.1 2025-09-29 19:55:02,233 [INFO] REQUEST: method=GET path=/fruits args={} body=None ip=127.0.0.1
2025-09-29 19:55:02,233 [INFO] RESPONSE: method=GET path=/fruits status=200 ip=127.0.0.1 2025-09-29 19:55:02,233 [INFO] RESPONSE: method=GET path=/fruits status=200 ip=127.0.0.1
2025-09-29 19:55:02,234 [INFO] 127.0.0.1 - - [29/Sep/2025 19:55:02] "GET /fruits HTTP/1.1" 200 - 2025-09-29 19:55:02,234 [INFO] 127.0.0.1 - - [29/Sep/2025 19:55:02] "GET /fruits HTTP/1.1" 200 -
2025-09-30 22:47:38,977 [INFO] WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.43.139:5000
2025-09-30 22:47:39,008 [INFO] Press CTRL+C to quit
2025-09-30 22:47:56,131 [INFO] REQUEST: method=GET path=/health args={} body=None ip=127.0.0.1
2025-09-30 22:47:56,132 [INFO] RESPONSE: method=GET path=/health status=200 ip=127.0.0.1
2025-09-30 22:47:56,133 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "GET /health HTTP/1.1" 200 -
2025-09-30 22:47:56,188 [INFO] REQUEST: method=GET path=/fruits args={} body=None ip=127.0.0.1
2025-09-30 22:47:56,189 [INFO] RESPONSE: method=GET path=/fruits status=200 ip=127.0.0.1
2025-09-30 22:47:56,189 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "GET /fruits HTTP/1.1" 200 -
2025-09-30 22:47:56,232 [INFO] REQUEST: method=GET path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:47:56,233 [INFO] RESPONSE: method=GET path=/fruits/1 status=200 ip=127.0.0.1
2025-09-30 22:47:56,234 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "GET /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:47:56,301 [INFO] REQUEST: method=POST path=/fruits args={} body={'name': 'Mango', 'color': 'Yellow', 'price': 2.5, 'quantity': 50, 'category': 'Tropical'} ip=127.0.0.1
2025-09-30 22:47:56,302 [INFO] RESPONSE: method=POST path=/fruits status=201 ip=127.0.0.1
2025-09-30 22:47:56,302 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "POST /fruits HTTP/1.1" 201 -
2025-09-30 22:47:56,326 [INFO] REQUEST: method=PUT path=/fruits/1 args={} body={'name': 'Green Apple', 'price': 1.8} ip=127.0.0.1
2025-09-30 22:47:56,327 [INFO] RESPONSE: method=PUT path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:47:56,327 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "PUT /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:47:56,351 [INFO] REQUEST: method=DELETE path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:47:56,352 [INFO] RESPONSE: method=DELETE path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:47:56,352 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "DELETE /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:47:56,376 [INFO] REQUEST: method=GET path=/fruits/search args={'name': 'apple'} body=None ip=127.0.0.1
2025-09-30 22:47:56,377 [INFO] RESPONSE: method=GET path=/fruits/search status=404 ip=127.0.0.1
2025-09-30 22:47:56,377 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "GET /fruits/search?name=apple HTTP/1.1" 404 -
2025-09-30 22:47:56,403 [INFO] REQUEST: method=GET path=/fruits/category/Tropical args={} body=None ip=127.0.0.1
2025-09-30 22:47:56,403 [INFO] RESPONSE: method=GET path=/fruits/category/Tropical status=404 ip=127.0.0.1
2025-09-30 22:47:56,404 [INFO] 127.0.0.1 - - [30/Sep/2025 22:47:56] "GET /fruits/category/Tropical HTTP/1.1" 404 -
2025-09-30 22:48:14,383 [INFO] REQUEST: method=GET path=/health args={} body=None ip=127.0.0.1
2025-09-30 22:48:14,383 [INFO] RESPONSE: method=GET path=/health status=200 ip=127.0.0.1
2025-09-30 22:48:14,384 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "GET /health HTTP/1.1" 200 -
2025-09-30 22:48:14,435 [INFO] REQUEST: method=GET path=/fruits args={} body=None ip=127.0.0.1
2025-09-30 22:48:14,436 [INFO] RESPONSE: method=GET path=/fruits status=200 ip=127.0.0.1
2025-09-30 22:48:14,437 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "GET /fruits HTTP/1.1" 200 -
2025-09-30 22:48:14,484 [INFO] REQUEST: method=GET path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:48:14,484 [INFO] RESPONSE: method=GET path=/fruits/1 status=200 ip=127.0.0.1
2025-09-30 22:48:14,485 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "GET /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:48:14,533 [INFO] REQUEST: method=POST path=/fruits args={} body={'name': 'Mango', 'color': 'Yellow', 'price': 2.5, 'quantity': 50, 'category': 'Tropical'} ip=127.0.0.1
2025-09-30 22:48:14,534 [INFO] RESPONSE: method=POST path=/fruits status=201 ip=127.0.0.1
2025-09-30 22:48:14,536 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "POST /fruits HTTP/1.1" 201 -
2025-09-30 22:48:14,595 [INFO] REQUEST: method=PUT path=/fruits/1 args={} body={'name': 'Green Apple', 'price': 1.8} ip=127.0.0.1
2025-09-30 22:48:14,596 [INFO] RESPONSE: method=PUT path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:48:14,596 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "PUT /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:48:14,648 [INFO] REQUEST: method=DELETE path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:48:14,649 [INFO] RESPONSE: method=DELETE path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:48:14,649 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "DELETE /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:48:14,669 [INFO] REQUEST: method=GET path=/fruits/search args={'name': 'apple'} body=None ip=127.0.0.1
2025-09-30 22:48:14,669 [INFO] RESPONSE: method=GET path=/fruits/search status=404 ip=127.0.0.1
2025-09-30 22:48:14,670 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "GET /fruits/search?name=apple HTTP/1.1" 404 -
2025-09-30 22:48:14,684 [INFO] REQUEST: method=GET path=/fruits/category/Tropical args={} body=None ip=127.0.0.1
2025-09-30 22:48:14,685 [INFO] RESPONSE: method=GET path=/fruits/category/Tropical status=404 ip=127.0.0.1
2025-09-30 22:48:14,685 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:14] "GET /fruits/category/Tropical HTTP/1.1" 404 -
2025-09-30 22:48:28,832 [INFO] REQUEST: method=GET path=/health args={} body=None ip=127.0.0.1
2025-09-30 22:48:28,832 [INFO] RESPONSE: method=GET path=/health status=200 ip=127.0.0.1
2025-09-30 22:48:28,834 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "GET /health HTTP/1.1" 200 -
2025-09-30 22:48:28,850 [INFO] REQUEST: method=GET path=/fruits args={} body=None ip=127.0.0.1
2025-09-30 22:48:28,851 [INFO] RESPONSE: method=GET path=/fruits status=200 ip=127.0.0.1
2025-09-30 22:48:28,851 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "GET /fruits HTTP/1.1" 200 -
2025-09-30 22:48:28,873 [INFO] REQUEST: method=GET path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:48:28,874 [INFO] RESPONSE: method=GET path=/fruits/1 status=200 ip=127.0.0.1
2025-09-30 22:48:28,874 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "GET /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:48:28,893 [INFO] REQUEST: method=POST path=/fruits args={} body={'name': 'Mango', 'color': 'Yellow', 'price': 2.5, 'quantity': 50, 'category': 'Tropical'} ip=127.0.0.1
2025-09-30 22:48:28,894 [INFO] RESPONSE: method=POST path=/fruits status=201 ip=127.0.0.1
2025-09-30 22:48:28,895 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "POST /fruits HTTP/1.1" 201 -
2025-09-30 22:48:28,914 [INFO] REQUEST: method=PUT path=/fruits/1 args={} body={'name': 'Green Apple', 'price': 1.8} ip=127.0.0.1
2025-09-30 22:48:28,915 [INFO] RESPONSE: method=PUT path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:48:28,915 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "PUT /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:48:28,939 [INFO] REQUEST: method=DELETE path=/fruits/1 args={} body=None ip=127.0.0.1
2025-09-30 22:48:28,940 [INFO] RESPONSE: method=DELETE path=/fruits/1 status=405 ip=127.0.0.1
2025-09-30 22:48:28,940 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "DELETE /fruits/1 HTTP/1.1" 405 -
2025-09-30 22:48:28,960 [INFO] REQUEST: method=GET path=/fruits/search args={'name': 'apple'} body=None ip=127.0.0.1
2025-09-30 22:48:28,960 [INFO] RESPONSE: method=GET path=/fruits/search status=404 ip=127.0.0.1
2025-09-30 22:48:28,960 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "GET /fruits/search?name=apple HTTP/1.1" 404 -
2025-09-30 22:48:28,977 [INFO] REQUEST: method=GET path=/fruits/category/Tropical args={} body=None ip=127.0.0.1
2025-09-30 22:48:28,977 [INFO] RESPONSE: method=GET path=/fruits/category/Tropical status=404 ip=127.0.0.1
2025-09-30 22:48:28,978 [INFO] 127.0.0.1 - - [30/Sep/2025 22:48:28] "GET /fruits/category/Tropical HTTP/1.1" 404 -
2025-09-30 22:53:33,909 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.43.139:5000
2025-09-30 22:53:33,921 - INFO - Press CTRL+C to quit
2025-09-30 22:53:33,932 - INFO - * Restarting with stat
2025-09-30 22:53:34,272 - WARNING - * Debugger is active!
2025-09-30 22:53:34,288 - INFO - * Debugger PIN: 117-497-176
2025-09-30 22:53:43,983 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.43.139:5000
2025-09-30 22:53:43,985 - INFO - Press CTRL+C to quit
2025-09-30 22:53:43,986 - INFO - * Restarting with stat
2025-09-30 22:53:44,149 - WARNING - * Debugger is active!
2025-09-30 22:53:44,153 - INFO - * Debugger PIN: 117-497-176
2025-09-30 22:53:52,705 - INFO - REQUEST: GET / - From 127.0.0.1
2025-09-30 22:53:52,707 - INFO - RESPONSE: GET / - Status 200
2025-09-30 22:53:52,708 - INFO - 127.0.0.1 - - [30/Sep/2025 22:53:52] "GET / HTTP/1.1" 200 -
2025-09-30 22:53:53,367 - INFO - REQUEST: GET /favicon.ico - From 127.0.0.1
2025-09-30 22:53:53,367 - INFO - RESPONSE: GET /favicon.ico - Status 404
2025-09-30 22:53:53,367 - INFO - 127.0.0.1 - - [30/Sep/2025 22:53:53] "GET /favicon.ico HTTP/1.1" 404 -
2025-09-30 22:54:01,228 - INFO - REQUEST: GET /health - From 127.0.0.1
2025-09-30 22:54:01,228 - INFO - RESPONSE: GET /health - Status 200
2025-09-30 22:54:01,229 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "GET /health HTTP/1.1" 200 -
2025-09-30 22:54:01,275 - INFO - REQUEST: GET /fruits - From 127.0.0.1
2025-09-30 22:54:01,275 - INFO - RESPONSE: GET /fruits - Status 200
2025-09-30 22:54:01,276 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "GET /fruits HTTP/1.1" 200 -
2025-09-30 22:54:01,332 - INFO - REQUEST: GET /fruits/1 - From 127.0.0.1
2025-09-30 22:54:01,333 - INFO - RESPONSE: GET /fruits/1 - Status 200
2025-09-30 22:54:01,334 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "GET /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:54:01,375 - INFO - REQUEST: POST /fruits - From 127.0.0.1
2025-09-30 22:54:01,376 - INFO - RESPONSE: POST /fruits - Status 201
2025-09-30 22:54:01,377 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "POST /fruits HTTP/1.1" 201 -
2025-09-30 22:54:01,426 - INFO - REQUEST: PUT /fruits/1 - From 127.0.0.1
2025-09-30 22:54:01,427 - INFO - RESPONSE: PUT /fruits/1 - Status 200
2025-09-30 22:54:01,428 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "PUT /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:54:01,473 - INFO - REQUEST: DELETE /fruits/1 - From 127.0.0.1
2025-09-30 22:54:01,474 - INFO - RESPONSE: DELETE /fruits/1 - Status 200
2025-09-30 22:54:01,474 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "DELETE /fruits/1 HTTP/1.1" 200 -
2025-09-30 22:54:01,516 - INFO - REQUEST: GET /fruits/search - From 127.0.0.1
2025-09-30 22:54:01,516 - INFO - RESPONSE: GET /fruits/search - Status 200
2025-09-30 22:54:01,516 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "GET /fruits/search?name=apple HTTP/1.1" 200 -
2025-09-30 22:54:01,534 - INFO - REQUEST: GET /fruits/category/Tropical - From 127.0.0.1
2025-09-30 22:54:01,535 - INFO - RESPONSE: GET /fruits/category/Tropical - Status 200
2025-09-30 22:54:01,535 - INFO - 127.0.0.1 - - [30/Sep/2025 22:54:01] "GET /fruits/category/Tropical HTTP/1.1" 200 -
2025-09-30 22:55:23,112 - INFO - REQUEST: GET /docs - From 127.0.0.1
2025-09-30 22:55:23,113 - INFO - RESPONSE: GET /docs - Status 404
2025-09-30 22:55:23,114 - INFO - 127.0.0.1 - - [30/Sep/2025 22:55:23] "GET /docs HTTP/1.1" 404 -
2025-09-30 23:00:03,721 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.43.139:5000
2025-09-30 23:00:03,722 - INFO - Press CTRL+C to quit
2025-09-30 23:00:03,734 - INFO - * Restarting with stat
2025-09-30 23:00:04,003 - WARNING - * Debugger is active!
2025-09-30 23:00:04,009 - INFO - * Debugger PIN: 117-497-176
2025-09-30 23:00:06,690 - INFO - REQUEST: GET / - From 127.0.0.1
2025-09-30 23:00:06,692 - INFO - RESPONSE: GET / - Status 200
2025-09-30 23:00:06,693 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:06] "GET / HTTP/1.1" 200 -
2025-09-30 23:00:11,991 - INFO - REQUEST: GET /apidoce - From 127.0.0.1
2025-09-30 23:00:11,992 - INFO - RESPONSE: GET /apidoce - Status 404
2025-09-30 23:00:11,995 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:11] "GET /apidoce HTTP/1.1" 404 -
2025-09-30 23:00:18,194 - INFO - REQUEST: GET /apidocs - From 127.0.0.1
2025-09-30 23:00:18,196 - INFO - RESPONSE: GET /apidocs - Status 308
2025-09-30 23:00:18,197 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /apidocs HTTP/1.1" 308 -
2025-09-30 23:00:18,211 - INFO - REQUEST: GET /apidocs/ - From 127.0.0.1
2025-09-30 23:00:18,302 - INFO - RESPONSE: GET /apidocs/ - Status 200
2025-09-30 23:00:18,304 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /apidocs/ HTTP/1.1" 200 -
2025-09-30 23:00:18,371 - INFO - REQUEST: GET /flasgger_static/swagger-ui.css - From 127.0.0.1
2025-09-30 23:00:18,372 - INFO - REQUEST: GET /flasgger_static/swagger-ui-bundle.js - From 127.0.0.1
2025-09-30 23:00:18,374 - INFO - REQUEST: GET /flasgger_static/swagger-ui-standalone-preset.js - From 127.0.0.1
2025-09-30 23:00:18,375 - INFO - REQUEST: GET /flasgger_static/lib/jquery.min.js - From 127.0.0.1
2025-09-30 23:00:18,423 - INFO - RESPONSE: GET /flasgger_static/swagger-ui.css - Status 200
2025-09-30 23:00:18,438 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /flasgger_static/swagger-ui.css HTTP/1.1" 200 -
2025-09-30 23:00:18,441 - INFO - RESPONSE: GET /flasgger_static/lib/jquery.min.js - Status 200
2025-09-30 23:00:18,442 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /flasgger_static/lib/jquery.min.js HTTP/1.1" 200 -
2025-09-30 23:00:18,443 - INFO - RESPONSE: GET /flasgger_static/swagger-ui-standalone-preset.js - Status 200
2025-09-30 23:00:18,445 - INFO - RESPONSE: GET /flasgger_static/swagger-ui-bundle.js - Status 200
2025-09-30 23:00:18,449 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /flasgger_static/swagger-ui-standalone-preset.js HTTP/1.1" 200 -
2025-09-30 23:00:18,450 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:18] "GET /flasgger_static/swagger-ui-bundle.js HTTP/1.1" 200 -
2025-09-30 23:00:19,453 - INFO - REQUEST: GET /apispec_1.json - From 127.0.0.1
2025-09-30 23:00:19,454 - INFO - RESPONSE: GET /apispec_1.json - Status 200
2025-09-30 23:00:19,454 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:19] "GET /apispec_1.json HTTP/1.1" 200 -
2025-09-30 23:00:19,562 - INFO - REQUEST: GET /flasgger_static/favicon-32x32.png - From 127.0.0.1
2025-09-30 23:00:19,564 - INFO - RESPONSE: GET /flasgger_static/favicon-32x32.png - Status 200
2025-09-30 23:00:19,565 - INFO - 127.0.0.1 - - [30/Sep/2025 23:00:19] "GET /flasgger_static/favicon-32x32.png HTTP/1.1" 200 -
2025-09-30 23:02:02,020 - INFO - WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
* Running on all addresses (0.0.0.0)
* Running on http://127.0.0.1:5000
* Running on http://192.168.43.139:5000
2025-09-30 23:02:02,020 - INFO - Press CTRL+C to quit
2025-09-30 23:02:02,023 - INFO - * Restarting with stat
2025-09-30 23:02:02,281 - WARNING - * Debugger is active!
2025-09-30 23:02:02,292 - INFO - * Debugger PIN: 117-497-176
2025-09-30 23:02:10,832 - INFO - REQUEST: GET /apidocs/ - From 127.0.0.1
2025-09-30 23:02:10,908 - INFO - RESPONSE: GET /apidocs/ - Status 200
2025-09-30 23:02:10,910 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "GET /apidocs/ HTTP/1.1" 200 -
2025-09-30 23:02:10,966 - INFO - REQUEST: GET /flasgger_static/swagger-ui.css - From 127.0.0.1
2025-09-30 23:02:10,982 - INFO - REQUEST: GET /flasgger_static/swagger-ui-bundle.js - From 127.0.0.1
2025-09-30 23:02:10,984 - INFO - REQUEST: GET /flasgger_static/swagger-ui-standalone-preset.js - From 127.0.0.1
2025-09-30 23:02:10,986 - INFO - RESPONSE: GET /flasgger_static/swagger-ui.css - Status 304
2025-09-30 23:02:10,988 - INFO - REQUEST: GET /flasgger_static/lib/jquery.min.js - From 127.0.0.1
2025-09-30 23:02:10,989 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "GET /flasgger_static/swagger-ui.css HTTP/1.1" 304 -
2025-09-30 23:02:10,989 - INFO - RESPONSE: GET /flasgger_static/swagger-ui-bundle.js - Status 304
2025-09-30 23:02:10,991 - INFO - RESPONSE: GET /flasgger_static/swagger-ui-standalone-preset.js - Status 304
2025-09-30 23:02:10,993 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "GET /flasgger_static/swagger-ui-bundle.js HTTP/1.1" 304 -
2025-09-30 23:02:10,994 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "GET /flasgger_static/swagger-ui-standalone-preset.js HTTP/1.1" 304 -
2025-09-30 23:02:10,996 - INFO - RESPONSE: GET /flasgger_static/lib/jquery.min.js - Status 304
2025-09-30 23:02:10,999 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "GET /flasgger_static/lib/jquery.min.js HTTP/1.1" 304 -
2025-09-30 23:02:11,426 - INFO - REQUEST: GET /apispec_1.json - From 127.0.0.1
2025-09-30 23:02:11,427 - INFO - RESPONSE: GET /apispec_1.json - Status 200
2025-09-30 23:02:11,428 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:11] "GET /apispec_1.json HTTP/1.1" 200 -
2025-09-30 23:02:11,446 - INFO - REQUEST: GET /flasgger_static/favicon-32x32.png - From 127.0.0.1
2025-09-30 23:02:11,447 - INFO - RESPONSE: GET /flasgger_static/favicon-32x32.png - Status 304
2025-09-30 23:02:11,447 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:11] "GET /flasgger_static/favicon-32x32.png HTTP/1.1" 304 -
2025-09-30 23:03:14,463 - INFO - REQUEST: GET /apidocs/ - From 127.0.0.1
2025-09-30 23:03:14,466 - INFO - RESPONSE: GET /apidocs/ - Status 200
2025-09-30 23:03:14,468 - INFO - 127.0.0.1 - - [30/Sep/2025 23:03:14] "GET /apidocs/ HTTP/1.1" 200 -
2025-09-30 23:03:18,260 - INFO - REQUEST: GET /apispec_1.json - From 127.0.0.1
2025-09-30 23:03:18,262 - INFO - RESPONSE: GET /apispec_1.json - Status 200
2025-09-30 23:03:18,263 - INFO - 127.0.0.1 - - [30/Sep/2025 23:03:18] "GET /apispec_1.json HTTP/1.1" 200 -
2025-09-30 23:03:20,049 - INFO - REQUEST: GET /apispec_1.json - From 127.0.0.1
2025-09-30 23:03:20,050 - INFO - RESPONSE: GET /apispec_1.json - Status 200
2025-09-30 23:03:20,050 - INFO - 127.0.0.1 - - [30/Sep/2025 23:03:20] "GET /apispec_1.json HTTP/1.1" 200 -
2025-09-30 23:08:22,398 - INFO - REQUEST: GET /docs - From 127.0.0.1
2025-09-30 23:08:22,399 - INFO - RESPONSE: GET /docs - Status 404
2025-09-30 23:08:22,399 - INFO - 127.0.0.1 - - [30/Sep/2025 23:08:22] "GET /docs HTTP/1.1" 404 -

عرض الملف

@@ -1,91 +1,217 @@
# fruit_api.py from flask import Flask, request, jsonify
from flask import Flask, jsonify, request from flasgger import Swagger
from datetime import datetime from datetime import datetime
import logging
app = Flask(__name__) app = Flask(__name__)
# ----------------------- # Swagger configuration (serve UI at /docs)
# Logging Configuration app.config["SWAGGER"] = {
# ----------------------- "title": "Ahmed Gamal's Fruit API",
LOG_FILE = "fruit_api.log" "uiversion": 3,
"swagger_ui": True,
"specs_route": "/docs/" # force Swagger UI to mount at /docs
}
swagger = Swagger(app)
logging.basicConfig( # Root endpoint (http://localhost:5000/)
filename=LOG_FILE, @app.route("/", methods=["GET"])
level=logging.INFO, def home():
format="%(asctime)s [%(levelname)s] %(message)s", return jsonify({
) "message": "Welcome to Ahmed Gamal's Fruit API 🚀",
"docs_url": "/docs"
})
# In-memory database # Sample data
fruits = [ fruits = [
{"id": 1, "name": "Apple", "color": "Red", "price": 1.50, "quantity": 100, "category": "Tropical"}, {"id": 1, "name": "Apple", "color": "Red", "price": 1.5, "quantity": 100, "category": "Tropical"},
{"id": 2, "name": "Banana", "color": "Yellow", "price": 0.75, "quantity": 150, "category": "Tropical"}, {"id": 2, "name": "Banana", "color": "Yellow", "price": 0.75, "quantity": 150, "category": "Tropical"},
{"id": 3, "name": "Orange", "color": "Orange", "price": 1.20, "quantity": 80, "category": "Citrus"} {"id": 3, "name": "Orange", "color": "Orange", "price": 1.2, "quantity": 80, "category": "Citrus"}
] ]
# ----------------------- @app.route("/health", methods=["GET"])
# Logging Hooks def health():
# ----------------------- """
@app.before_request Health Check
def log_request(): ---
logging.info( tags:
f"REQUEST: method={request.method} path={request.path} " - Health
f"args={dict(request.args)} body={request.get_json(silent=True)} " responses:
f"ip={request.remote_addr}" 200:
) description: API is healthy
"""
return jsonify({
"service": "fruit-api",
"status": "healthy",
"timestamp": datetime.utcnow().isoformat()
})
@app.after_request @app.route("/fruits", methods=["GET"])
def log_response(response): def get_fruits():
logging.info( """
f"RESPONSE: method={request.method} path={request.path} " Get All Fruits
f"status={response.status_code} ip={request.remote_addr}" ---
) tags:
return response - Fruits
responses:
# ----------------------- 200:
# API Endpoints description: A list of all fruits
# ----------------------- """
@app.route('/')
def home():
return jsonify({"message": "Fruit Store API", "version": "1.0"})
@app.route('/fruits', methods=['GET'])
def get_all_fruits():
return jsonify({"fruits": fruits, "total": len(fruits)}) return jsonify({"fruits": fruits, "total": len(fruits)})
@app.route('/fruits/<int:fruit_id>', methods=['GET']) @app.route("/fruits/<int:fruit_id>", methods=["GET"])
def get_fruit(fruit_id): def get_fruit(fruit_id):
fruit = next((f for f in fruits if f['id'] == fruit_id), None) """
Get a Fruit by ID
---
tags:
- Fruits
parameters:
- name: fruit_id
in: path
type: integer
required: true
responses:
200:
description: Fruit details
404:
description: Fruit not found
"""
fruit = next((f for f in fruits if f["id"] == fruit_id), None)
if fruit: if fruit:
return jsonify({"fruit": fruit}) return jsonify({"fruit": fruit})
return jsonify({"error": "Fruit not found"}), 404 return jsonify({"error": "Fruit not found"}), 404
@app.route('/fruits', methods=['POST']) @app.route("/fruits", methods=["POST"])
def create_fruit(): def create_fruit():
"""
Create a New Fruit
---
tags:
- Fruits
parameters:
- name: body
in: body
required: true
schema:
type: object
properties:
name: {type: string}
color: {type: string}
price: {type: number}
quantity: {type: integer}
category: {type: string}
responses:
201:
description: Fruit created
"""
data = request.get_json() data = request.get_json()
if not data or 'name' not in data:
return jsonify({"error": "Name is required"}), 400
new_id = max([f['id'] for f in fruits]) + 1 if fruits else 1
new_fruit = { new_fruit = {
"id": new_id, "id": len(fruits) + 1,
"name": data['name'], "name": data.get("name"),
"color": data.get('color', 'Unknown'), "color": data.get("color"),
"price": data.get('price', 0.0), "price": data.get("price"),
"quantity": data.get('quantity', 0), "quantity": data.get("quantity"),
"category": data.get('category', 'General'), "category": data.get("category"),
"created_at": datetime.now().isoformat() "created_at": datetime.utcnow().isoformat()
} }
fruits.append(new_fruit) fruits.append(new_fruit)
return jsonify({"message": "Fruit created successfully", "fruit": new_fruit}), 201 return jsonify({"message": "Fruit created successfully", "fruit": new_fruit}), 201
@app.route('/health', methods=['GET']) @app.route("/fruits/<int:fruit_id>", methods=["PUT"])
def health_check(): def update_fruit(fruit_id):
return jsonify({"status": "healthy", "service": "fruit-api"}) """
Update a Fruit
---
tags:
- Fruits
parameters:
- name: fruit_id
in: path
type: integer
required: true
- name: body
in: body
required: true
schema:
type: object
responses:
200:
description: Fruit updated
404:
description: Fruit not found
"""
fruit = next((f for f in fruits if f["id"] == fruit_id), None)
if not fruit:
return jsonify({"error": "Fruit not found"}), 404
# ----------------------- data = request.get_json()
# Run API fruit.update(data)
# ----------------------- fruit["updated_at"] = datetime.utcnow().isoformat()
if __name__ == '__main__': return jsonify({"message": "Fruit updated successfully", "fruit": fruit})
print("Fruit API starting on http://localhost:5000")
app.run(debug=False, host='0.0.0.0', port=5000) @app.route("/fruits/<int:fruit_id>", methods=["DELETE"])
def delete_fruit(fruit_id):
"""
Delete a Fruit
---
tags:
- Fruits
parameters:
- name: fruit_id
in: path
type: integer
required: true
responses:
200:
description: Fruit deleted
404:
description: Fruit not found
"""
global fruits
fruit = next((f for f in fruits if f["id"] == fruit_id), None)
if not fruit:
return jsonify({"error": "Fruit not found"}), 404
fruits = [f for f in fruits if f["id"] != fruit_id]
return jsonify({"message": "Fruit deleted successfully", "deleted_fruit": fruit})
@app.route("/fruits/search", methods=["GET"])
def search_fruits():
"""
Search Fruits by Name
---
tags:
- Fruits
parameters:
- name: name
in: query
type: string
required: true
responses:
200:
description: Search results
"""
name = request.args.get("name", "").lower()
results = [f for f in fruits if name in f["name"].lower()]
return jsonify({"search_term": name, "count": len(results), "results": results})
@app.route("/fruits/category/<string:category>", methods=["GET"])
def get_fruits_by_category(category):
"""
Get Fruits by Category
---
tags:
- Fruits
parameters:
- name: category
in: path
type: string
required: true
responses:
200:
description: Fruits by category
"""
results = [f for f in fruits if f["category"].lower() == category.lower()]
return jsonify({"category": category, "count": len(results), "fruits": results})
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5000)

عرض الملف

@@ -1,2 +1,3 @@
# requirements.txt # requirements.txt
Flask==2.3.3 Flask==2.3.3
flasgger

57
test_api.sh Executable file
عرض الملف

@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# test_api.sh
# Script to test Fruit API endpoints and log responses
API_URL="http://localhost:5000"
LOG_FILE="test_results.log"
echo "🚀 Running API tests at $(date)" | tee -a "$LOG_FILE"
echo "======================================" | tee -a "$LOG_FILE"
# 1. Health Check
echo "🔹 Testing /health" | tee -a "$LOG_FILE"
curl -s -w "\nStatus: %{http_code}\n" "$API_URL/health" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 2. Get all fruits
echo "🔹 Testing GET /fruits" | tee -a "$LOG_FILE"
curl -s -w "\nStatus: %{http_code}\n" "$API_URL/fruits" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 3. Get fruit by ID (1)
echo "🔹 Testing GET /fruits/1" | tee -a "$LOG_FILE"
curl -s -w "\nStatus: %{http_code}\n" "$API_URL/fruits/1" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 4. Create new fruit
echo "🔹 Testing POST /fruits" | tee -a "$LOG_FILE"
curl -s -X POST -H "Content-Type: application/json" \
-d '{"name":"Mango","color":"Yellow","price":2.5,"quantity":50,"category":"Tropical"}' \
-w "\nStatus: %{http_code}\n" "$API_URL/fruits" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 5. Update fruit ID 1
echo "🔹 Testing PUT /fruits/1" | tee -a "$LOG_FILE"
curl -s -X PUT -H "Content-Type: application/json" \
-d '{"name":"Green Apple","price":1.8}' \
-w "\nStatus: %{http_code}\n" "$API_URL/fruits/1" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 6. Delete fruit ID 1
echo "🔹 Testing DELETE /fruits/1" | tee -a "$LOG_FILE"
curl -s -X DELETE -w "\nStatus: %{http_code}\n" "$API_URL/fruits/1" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 7. Search fruits
echo "🔹 Testing GET /fruits/search?name=apple" | tee -a "$LOG_FILE"
curl -s -w "\nStatus: %{http_code}\n" "$API_URL/fruits/search?name=apple" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
# 8. Get fruits by category
echo "🔹 Testing GET /fruits/category/Tropical" | tee -a "$LOG_FILE"
curl -s -w "\nStatus: %{http_code}\n" "$API_URL/fruits/category/Tropical" | tee -a "$LOG_FILE"
echo "--------------------------------------" | tee -a "$LOG_FILE"
echo "✅ Tests completed at $(date)" | tee -a "$LOG_FILE"
echo "======================================" | tee -a "$LOG_FILE"

505
test_results.log Normal file
عرض الملف

@@ -0,0 +1,505 @@
🚀 Running API tests at Tue 30 Sep 2025 10:43:38 PM EEST
======================================
🔹 Testing /health
Status: 000
--------------------------------------
🔹 Testing GET /fruits
Status: 000
--------------------------------------
🔹 Testing GET /fruits/1
Status: 000
--------------------------------------
🔹 Testing POST /fruits
Status: 000
--------------------------------------
🔹 Testing PUT /fruits/1
Status: 000
--------------------------------------
🔹 Testing DELETE /fruits/1
Status: 000
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
Status: 000
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
Status: 000
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 10:43:39 PM EEST
======================================
🚀 Running API tests at Tue 30 Sep 2025 10:47:56 PM EEST
======================================
🔹 Testing /health
{"service":"fruit-api","status":"healthy"}
Status: 200
--------------------------------------
🔹 Testing GET /fruits
{"fruits":[{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100},{"category":"Tropical","color":"Yellow","id":2,"name":"Banana","price":0.75,"quantity":150},{"category":"Citrus","color":"Orange","id":3,"name":"Orange","price":1.2,"quantity":80}],"total":3}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/1
{"fruit":{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100}}
Status: 200
--------------------------------------
🔹 Testing POST /fruits
{"fruit":{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:47:56.301904","id":4,"name":"Mango","price":2.5,"quantity":50},"message":"Fruit created successfully"}
Status: 201
--------------------------------------
🔹 Testing PUT /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing DELETE /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 10:47:56 PM EEST
======================================
🚀 Running API tests at Tue 30 Sep 2025 10:48:14 PM EEST
======================================
🔹 Testing /health
{"service":"fruit-api","status":"healthy"}
Status: 200
--------------------------------------
🔹 Testing GET /fruits
{"fruits":[{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100},{"category":"Tropical","color":"Yellow","id":2,"name":"Banana","price":0.75,"quantity":150},{"category":"Citrus","color":"Orange","id":3,"name":"Orange","price":1.2,"quantity":80},{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:47:56.301904","id":4,"name":"Mango","price":2.5,"quantity":50}],"total":4}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/1
{"fruit":{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100}}
Status: 200
--------------------------------------
🔹 Testing POST /fruits
{"fruit":{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:48:14.534108","id":5,"name":"Mango","price":2.5,"quantity":50},"message":"Fruit created successfully"}
Status: 201
--------------------------------------
🔹 Testing PUT /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing DELETE /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 10:48:14 PM EEST
======================================
🚀 Running API tests at Tue 30 Sep 2025 10:48:28 PM EEST
======================================
🔹 Testing /health
{"service":"fruit-api","status":"healthy"}
Status: 200
--------------------------------------
🔹 Testing GET /fruits
{"fruits":[{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100},{"category":"Tropical","color":"Yellow","id":2,"name":"Banana","price":0.75,"quantity":150},{"category":"Citrus","color":"Orange","id":3,"name":"Orange","price":1.2,"quantity":80},{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:47:56.301904","id":4,"name":"Mango","price":2.5,"quantity":50},{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:48:14.534108","id":5,"name":"Mango","price":2.5,"quantity":50}],"total":5}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/1
{"fruit":{"category":"Tropical","color":"Red","id":1,"name":"Apple","price":1.5,"quantity":100}}
Status: 200
--------------------------------------
🔹 Testing POST /fruits
{"fruit":{"category":"Tropical","color":"Yellow","created_at":"2025-09-30T22:48:28.894050","id":6,"name":"Mango","price":2.5,"quantity":50},"message":"Fruit created successfully"}
Status: 201
--------------------------------------
🔹 Testing PUT /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing DELETE /fruits/1
<!doctype html>
<html lang=en>
<title>405 Method Not Allowed</title>
<h1>Method Not Allowed</h1>
<p>The method is not allowed for the requested URL.</p>
Status: 405
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
<!doctype html>
<html lang=en>
<title>404 Not Found</title>
<h1>Not Found</h1>
<p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.</p>
Status: 404
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 10:48:28 PM EEST
======================================
🚀 Running API tests at Tue 30 Sep 2025 10:54:01 PM EEST
======================================
🔹 Testing /health
{
"service": "fruit-api",
"status": "healthy",
"timestamp": "2025-09-30T22:54:01.228357"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits
{
"fruits": [
{
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Apple",
"price": 1.5,
"quantity": 100
},
{
"category": "Tropical",
"color": "Yellow",
"id": 2,
"name": "Banana",
"price": 0.75,
"quantity": 150
},
{
"category": "Citrus",
"color": "Orange",
"id": 3,
"name": "Orange",
"price": 1.2,
"quantity": 80
}
],
"timestamp": "2025-09-30T22:54:01.275312",
"total": 3
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/1
{
"fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Apple",
"price": 1.5,
"quantity": 100
}
}
Status: 200
--------------------------------------
🔹 Testing POST /fruits
{
"fruit": {
"category": "Tropical",
"color": "Yellow",
"created_at": "2025-09-30T22:54:01.376254",
"id": 4,
"name": "Mango",
"price": 2.5,
"quantity": 50
},
"message": "Fruit created successfully"
}
Status: 201
--------------------------------------
🔹 Testing PUT /fruits/1
{
"fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Green Apple",
"price": 1.8,
"quantity": 100,
"updated_at": "2025-09-30T22:54:01.427456"
},
"message": "Fruit updated successfully"
}
Status: 200
--------------------------------------
🔹 Testing DELETE /fruits/1
{
"deleted_fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Green Apple",
"price": 1.8,
"quantity": 100,
"updated_at": "2025-09-30T22:54:01.427456"
},
"message": "Fruit deleted successfully"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
{
"count": 0,
"results": [],
"search_term": "apple"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
{
"category": "Tropical",
"count": 2,
"fruits": [
{
"category": "Tropical",
"color": "Yellow",
"id": 2,
"name": "Banana",
"price": 0.75,
"quantity": 150
},
{
"category": "Tropical",
"color": "Yellow",
"created_at": "2025-09-30T22:54:01.376254",
"id": 4,
"name": "Mango",
"price": 2.5,
"quantity": 50
}
]
}
Status: 200
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 10:54:01 PM EEST
======================================
🚀 Running API tests at Tue 30 Sep 2025 11:14:57 PM EEST
======================================
🔹 Testing /health
{
"service": "fruit-api",
"status": "healthy",
"timestamp": "2025-09-30T20:14:57.077152"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits
{
"fruits": [
{
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Apple",
"price": 1.5,
"quantity": 100
},
{
"category": "Tropical",
"color": "Yellow",
"id": 2,
"name": "Banana",
"price": 0.75,
"quantity": 150
},
{
"category": "Citrus",
"color": "Orange",
"id": 3,
"name": "Orange",
"price": 1.2,
"quantity": 80
}
],
"total": 3
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/1
{
"fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Apple",
"price": 1.5,
"quantity": 100
}
}
Status: 200
--------------------------------------
🔹 Testing POST /fruits
{
"fruit": {
"category": "Tropical",
"color": "Yellow",
"created_at": "2025-09-30T20:14:57.129021",
"id": 4,
"name": "Mango",
"price": 2.5,
"quantity": 50
},
"message": "Fruit created successfully"
}
Status: 201
--------------------------------------
🔹 Testing PUT /fruits/1
{
"fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Green Apple",
"price": 1.8,
"quantity": 100,
"updated_at": "2025-09-30T20:14:57.150810"
},
"message": "Fruit updated successfully"
}
Status: 200
--------------------------------------
🔹 Testing DELETE /fruits/1
{
"deleted_fruit": {
"category": "Tropical",
"color": "Red",
"id": 1,
"name": "Green Apple",
"price": 1.8,
"quantity": 100,
"updated_at": "2025-09-30T20:14:57.150810"
},
"message": "Fruit deleted successfully"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/search?name=apple
{
"count": 0,
"results": [],
"search_term": "apple"
}
Status: 200
--------------------------------------
🔹 Testing GET /fruits/category/Tropical
{
"category": "Tropical",
"count": 2,
"fruits": [
{
"category": "Tropical",
"color": "Yellow",
"id": 2,
"name": "Banana",
"price": 0.75,
"quantity": 150
},
{
"category": "Tropical",
"color": "Yellow",
"created_at": "2025-09-30T20:14:57.129021",
"id": 4,
"name": "Mango",
"price": 2.5,
"quantity": 50
}
]
}
Status: 200
--------------------------------------
✅ Tests completed at Tue 30 Sep 2025 11:14:57 PM EEST
======================================