Adding Swagger Docs endpoint & API Test Script
هذا الالتزام موجود في:
205
fruit_api.log
205
fruit_api.log
@@ -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] [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||||
|
* 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] [33mPress CTRL+C to quit[0m
|
||||||
|
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] "[35m[1mPOST /fruits HTTP/1.1[0m" 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] "[31m[1mPUT /fruits/1 HTTP/1.1[0m" 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] "[31m[1mDELETE /fruits/1 HTTP/1.1[0m" 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] "[33mGET /fruits/search?name=apple HTTP/1.1[0m" 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] "[33mGET /fruits/category/Tropical HTTP/1.1[0m" 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] "[35m[1mPOST /fruits HTTP/1.1[0m" 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] "[31m[1mPUT /fruits/1 HTTP/1.1[0m" 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] "[31m[1mDELETE /fruits/1 HTTP/1.1[0m" 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] "[33mGET /fruits/search?name=apple HTTP/1.1[0m" 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] "[33mGET /fruits/category/Tropical HTTP/1.1[0m" 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] "[35m[1mPOST /fruits HTTP/1.1[0m" 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] "[31m[1mPUT /fruits/1 HTTP/1.1[0m" 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] "[31m[1mDELETE /fruits/1 HTTP/1.1[0m" 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] "[33mGET /fruits/search?name=apple HTTP/1.1[0m" 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] "[33mGET /fruits/category/Tropical HTTP/1.1[0m" 404 -
|
||||||
|
2025-09-30 22:53:33,909 - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||||
|
* 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 - [33mPress CTRL+C to quit[0m
|
||||||
|
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 - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||||
|
* 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 - [33mPress CTRL+C to quit[0m
|
||||||
|
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] "[33mGET /favicon.ico HTTP/1.1[0m" 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] "[35m[1mPOST /fruits HTTP/1.1[0m" 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] "[33mGET /docs HTTP/1.1[0m" 404 -
|
||||||
|
2025-09-30 23:00:03,721 - INFO - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||||
|
* 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 - [33mPress CTRL+C to quit[0m
|
||||||
|
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] "[33mGET /apidoce HTTP/1.1[0m" 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] "[32mGET /apidocs HTTP/1.1[0m" 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 - [31m[1mWARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.[0m
|
||||||
|
* 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 - [33mPress CTRL+C to quit[0m
|
||||||
|
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] "[36mGET /flasgger_static/swagger-ui.css HTTP/1.1[0m" 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] "[36mGET /flasgger_static/swagger-ui-bundle.js HTTP/1.1[0m" 304 -
|
||||||
|
2025-09-30 23:02:10,994 - INFO - 127.0.0.1 - - [30/Sep/2025 23:02:10] "[36mGET /flasgger_static/swagger-ui-standalone-preset.js HTTP/1.1[0m" 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] "[36mGET /flasgger_static/lib/jquery.min.js HTTP/1.1[0m" 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] "[36mGET /flasgger_static/favicon-32x32.png HTTP/1.1[0m" 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] "[33mGET /docs HTTP/1.1[0m" 404 -
|
||||||
|
256
fruit_api.py
256
fruit_api.py
@@ -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
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
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
|
||||||
|
======================================
|
المرجع في مشكلة جديدة
حظر مستخدم