Nipun commited on
Commit
a4a1f1b
·
0 Parent(s):

Initial commit: FastAPI teaching tool

Browse files
Files changed (5) hide show
  1. .gitignore +9 -0
  2. Dockerfile +12 -0
  3. README.md +134 -0
  4. app.py +418 -0
  5. requirements.txt +3 -0
.gitignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+ .venv/
5
+ venv/
6
+ .env
7
+ *.egg-info/
8
+ dist/
9
+ build/
Dockerfile ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ COPY requirements.txt .
6
+ RUN pip install --no-cache-dir -r requirements.txt
7
+
8
+ COPY app.py .
9
+
10
+ EXPOSE 7860
11
+
12
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README.md ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: API Teaching Tool
3
+ emoji: 🔌
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: docker
7
+ pinned: false
8
+ license: mit
9
+ ---
10
+
11
+ # API Teaching Tool
12
+
13
+ A simple educational API for learning HTTP methods, request/response formats, and REST API concepts.
14
+
15
+ ## Quick Start
16
+
17
+ Once deployed, visit `/docs` for interactive Swagger documentation.
18
+
19
+ ## Endpoints Overview
20
+
21
+ ### GET Examples
22
+ | Endpoint | Description |
23
+ |----------|-------------|
24
+ | `/hello` | Simplest GET - returns greeting |
25
+ | `/time` | Returns current server time |
26
+ | `/greet?name=X` | Query parameter example |
27
+ | `/greet/{name}` | Path parameter example |
28
+ | `/search?q=X&limit=10` | Multiple query parameters |
29
+ | `/items` | List all items |
30
+ | `/items/{id}` | Get single item |
31
+
32
+ ### POST Examples
33
+ | Endpoint | Description |
34
+ |----------|-------------|
35
+ | `/items` | Create new item (JSON body) |
36
+ | `/users` | Create user (JSON body) |
37
+ | `/echo` | Echo back any JSON you send |
38
+ | `/echo/text` | Echo back raw text |
39
+
40
+ ### PUT/PATCH/DELETE
41
+ | Endpoint | Method | Description |
42
+ |----------|--------|-------------|
43
+ | `/items/{id}` | PUT | Replace entire item |
44
+ | `/items/{id}` | PATCH | Partial update |
45
+ | `/items/{id}` | DELETE | Delete item |
46
+
47
+ ### Response Formats
48
+ | Endpoint | Format |
49
+ |----------|--------|
50
+ | `/format/json` | JSON (default) |
51
+ | `/format/text` | Plain text |
52
+ | `/format/html` | HTML page |
53
+ | `/format/xml` | XML document |
54
+
55
+ ### Educational
56
+ | Endpoint | Description |
57
+ |----------|-------------|
58
+ | `/headers` | Shows all request headers |
59
+ | `/headers/custom` | Returns custom headers |
60
+ | `/status/{code}` | Returns specified HTTP status |
61
+ | `/method` | Accepts any method, shows what was used |
62
+ | `/ip` | Shows client IP address |
63
+ | `/params/types` | Demonstrates parameter types |
64
+
65
+ ## Example Usage
66
+
67
+ ### Using curl
68
+
69
+ ```bash
70
+ # Simple GET
71
+ curl https://nipun-api-testing.hf.space/hello
72
+
73
+ # GET with query parameter
74
+ curl "https://nipun-api-testing.hf.space/greet?name=Alice"
75
+
76
+ # POST with JSON body
77
+ curl -X POST https://nipun-api-testing.hf.space/items \
78
+ -H "Content-Type: application/json" \
79
+ -d '{"name": "Book", "price": 15.99, "quantity": 10}'
80
+
81
+ # PUT to update
82
+ curl -X PUT https://nipun-api-testing.hf.space/items/1 \
83
+ -H "Content-Type: application/json" \
84
+ -d '{"name": "Updated Apple", "price": 2.00, "quantity": 50}'
85
+
86
+ # DELETE
87
+ curl -X DELETE https://nipun-api-testing.hf.space/items/1
88
+
89
+ # Get different formats
90
+ curl https://nipun-api-testing.hf.space/format/xml
91
+ curl https://nipun-api-testing.hf.space/format/html
92
+
93
+ # Test status codes
94
+ curl -i https://nipun-api-testing.hf.space/status/404
95
+ curl -i https://nipun-api-testing.hf.space/status/201
96
+ ```
97
+
98
+ ### Using Python requests
99
+
100
+ ```python
101
+ import requests
102
+
103
+ BASE = "https://nipun-api-testing.hf.space"
104
+
105
+ # GET request
106
+ response = requests.get(f"{BASE}/hello")
107
+ print(response.json())
108
+
109
+ # GET with parameters
110
+ response = requests.get(f"{BASE}/greet", params={"name": "Alice"})
111
+ print(response.json())
112
+
113
+ # POST with JSON
114
+ data = {"name": "Laptop", "price": 999.99, "quantity": 5}
115
+ response = requests.post(f"{BASE}/items", json=data)
116
+ print(response.status_code) # 201
117
+ print(response.json())
118
+
119
+ # Check headers
120
+ response = requests.get(f"{BASE}/headers")
121
+ print(response.json())
122
+ ```
123
+
124
+ ## Local Development
125
+
126
+ ```bash
127
+ pip install -r requirements.txt
128
+ python app.py
129
+ # Visit http://localhost:7860/docs
130
+ ```
131
+
132
+ ## License
133
+
134
+ MIT
app.py ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Educational API for Teaching HTTP Methods & Response Formats
3
+ ============================================================
4
+ A simple FastAPI application designed for teaching REST API concepts.
5
+
6
+ Endpoints cover:
7
+ - HTTP Methods: GET, POST, PUT, DELETE, PATCH
8
+ - Response Formats: JSON, XML, Plain Text, HTML
9
+ - Query Parameters, Path Parameters, Request Bodies
10
+ - Headers, Status Codes, and more
11
+ """
12
+
13
+ from fastapi import FastAPI, Query, Path, Body, Header, Response, HTTPException, Request
14
+ from fastapi.responses import PlainTextResponse, HTMLResponse, JSONResponse
15
+ from pydantic import BaseModel, Field
16
+ from typing import Optional, List
17
+ from datetime import datetime
18
+ import json
19
+
20
+ app = FastAPI(
21
+ title="API Teaching Tool",
22
+ description="Educational API for learning HTTP methods, parameters, and response formats",
23
+ version="1.0.0",
24
+ )
25
+
26
+ # ============================================================================
27
+ # DATA MODELS
28
+ # ============================================================================
29
+
30
+ class Item(BaseModel):
31
+ """A simple item model for POST/PUT examples"""
32
+ name: str = Field(..., example="Laptop")
33
+ price: float = Field(..., example=999.99)
34
+ quantity: int = Field(default=1, example=5)
35
+ description: Optional[str] = Field(default=None, example="A powerful laptop")
36
+
37
+ class User(BaseModel):
38
+ """User model for registration examples"""
39
+ username: str = Field(..., example="john_doe")
40
+ email: str = Field(..., example="john@example.com")
41
+ age: Optional[int] = Field(default=None, example=25)
42
+
43
+ class Message(BaseModel):
44
+ """Simple message model"""
45
+ text: str = Field(..., example="Hello, World!")
46
+
47
+ # In-memory storage for demo purposes
48
+ items_db = {
49
+ 1: {"id": 1, "name": "Apple", "price": 1.50, "quantity": 100, "description": "Fresh red apple"},
50
+ 2: {"id": 2, "name": "Banana", "price": 0.75, "quantity": 150, "description": "Yellow banana"},
51
+ 3: {"id": 3, "name": "Orange", "price": 2.00, "quantity": 80, "description": "Juicy orange"},
52
+ }
53
+ next_id = 4
54
+
55
+ # ============================================================================
56
+ # ROOT & INFO ENDPOINTS
57
+ # ============================================================================
58
+
59
+ @app.get("/", tags=["Info"])
60
+ def root():
61
+ """Welcome endpoint with API overview"""
62
+ return {
63
+ "message": "Welcome to the API Teaching Tool!",
64
+ "documentation": "/docs",
65
+ "endpoints": {
66
+ "GET examples": ["/hello", "/items", "/items/{id}", "/greet"],
67
+ "POST examples": ["/items", "/echo", "/users"],
68
+ "PUT examples": ["/items/{id}"],
69
+ "DELETE examples": ["/items/{id}"],
70
+ "PATCH examples": ["/items/{id}"],
71
+ "Response formats": ["/format/json", "/format/text", "/format/html", "/format/xml"],
72
+ "Educational": ["/echo", "/headers", "/status/{code}", "/delay/{seconds}"],
73
+ }
74
+ }
75
+
76
+ # ============================================================================
77
+ # SIMPLE GET ENDPOINTS
78
+ # ============================================================================
79
+
80
+ @app.get("/hello", tags=["GET Examples"])
81
+ def hello():
82
+ """Simplest GET endpoint - returns a greeting"""
83
+ return {"message": "Hello, World!"}
84
+
85
+ @app.get("/time", tags=["GET Examples"])
86
+ def get_time():
87
+ """Returns current server time"""
88
+ now = datetime.now()
89
+ return {
90
+ "current_time": now.isoformat(),
91
+ "timestamp": now.timestamp(),
92
+ "formatted": now.strftime("%B %d, %Y at %I:%M %p")
93
+ }
94
+
95
+ @app.get("/greet", tags=["GET Examples"])
96
+ def greet(name: str = Query(default="Guest", description="Your name")):
97
+ """GET with query parameter - /greet?name=YourName"""
98
+ return {"message": f"Hello, {name}!", "parameter_received": name}
99
+
100
+ @app.get("/greet/{name}", tags=["GET Examples"])
101
+ def greet_path(name: str = Path(..., description="Your name in the URL path")):
102
+ """GET with path parameter - /greet/YourName"""
103
+ return {"message": f"Hello, {name}!", "path_parameter": name}
104
+
105
+ @app.get("/search", tags=["GET Examples"])
106
+ def search(
107
+ q: str = Query(..., description="Search query (required)"),
108
+ limit: int = Query(default=10, ge=1, le=100, description="Max results"),
109
+ offset: int = Query(default=0, ge=0, description="Skip first N results"),
110
+ sort: str = Query(default="relevance", description="Sort by: relevance, date, name")
111
+ ):
112
+ """GET with multiple query parameters - demonstrates pagination"""
113
+ return {
114
+ "query": q,
115
+ "limit": limit,
116
+ "offset": offset,
117
+ "sort": sort,
118
+ "explanation": "This shows how query parameters work for filtering/pagination",
119
+ "example_url": f"/search?q={q}&limit={limit}&offset={offset}&sort={sort}"
120
+ }
121
+
122
+ # ============================================================================
123
+ # CRUD OPERATIONS ON ITEMS
124
+ # ============================================================================
125
+
126
+ @app.get("/items", tags=["CRUD - Items"])
127
+ def list_items():
128
+ """GET all items"""
129
+ return {"items": list(items_db.values()), "count": len(items_db)}
130
+
131
+ @app.get("/items/{item_id}", tags=["CRUD - Items"])
132
+ def get_item(item_id: int = Path(..., description="The ID of the item to retrieve")):
133
+ """GET a single item by ID"""
134
+ if item_id not in items_db:
135
+ raise HTTPException(status_code=404, detail=f"Item with id {item_id} not found")
136
+ return items_db[item_id]
137
+
138
+ @app.post("/items", status_code=201, tags=["CRUD - Items"])
139
+ def create_item(item: Item):
140
+ """POST - Create a new item"""
141
+ global next_id
142
+ new_item = {"id": next_id, **item.model_dump()}
143
+ items_db[next_id] = new_item
144
+ next_id += 1
145
+ return {"message": "Item created successfully", "item": new_item}
146
+
147
+ @app.put("/items/{item_id}", tags=["CRUD - Items"])
148
+ def update_item(item_id: int, item: Item):
149
+ """PUT - Replace an entire item"""
150
+ if item_id not in items_db:
151
+ raise HTTPException(status_code=404, detail=f"Item with id {item_id} not found")
152
+ updated_item = {"id": item_id, **item.model_dump()}
153
+ items_db[item_id] = updated_item
154
+ return {"message": "Item updated successfully", "item": updated_item}
155
+
156
+ @app.patch("/items/{item_id}", tags=["CRUD - Items"])
157
+ def partial_update_item(
158
+ item_id: int,
159
+ name: Optional[str] = Body(default=None),
160
+ price: Optional[float] = Body(default=None),
161
+ quantity: Optional[int] = Body(default=None),
162
+ description: Optional[str] = Body(default=None)
163
+ ):
164
+ """PATCH - Partially update an item (only send fields to change)"""
165
+ if item_id not in items_db:
166
+ raise HTTPException(status_code=404, detail=f"Item with id {item_id} not found")
167
+
168
+ current_item = items_db[item_id]
169
+ if name is not None:
170
+ current_item["name"] = name
171
+ if price is not None:
172
+ current_item["price"] = price
173
+ if quantity is not None:
174
+ current_item["quantity"] = quantity
175
+ if description is not None:
176
+ current_item["description"] = description
177
+
178
+ return {"message": "Item partially updated", "item": current_item}
179
+
180
+ @app.delete("/items/{item_id}", tags=["CRUD - Items"])
181
+ def delete_item(item_id: int):
182
+ """DELETE - Remove an item"""
183
+ if item_id not in items_db:
184
+ raise HTTPException(status_code=404, detail=f"Item with id {item_id} not found")
185
+ deleted_item = items_db.pop(item_id)
186
+ return {"message": "Item deleted successfully", "deleted_item": deleted_item}
187
+
188
+ # ============================================================================
189
+ # POST EXAMPLES
190
+ # ============================================================================
191
+
192
+ @app.post("/users", status_code=201, tags=["POST Examples"])
193
+ def create_user(user: User):
194
+ """POST - Create a new user (demonstrates JSON body)"""
195
+ return {
196
+ "message": "User created successfully",
197
+ "user": user.model_dump(),
198
+ "note": "In a real app, this would save to a database"
199
+ }
200
+
201
+ @app.post("/echo", tags=["POST Examples"])
202
+ def echo_body(data: dict = Body(...)):
203
+ """POST - Echo back whatever JSON you send"""
204
+ return {
205
+ "received": data,
206
+ "type": str(type(data).__name__),
207
+ "keys": list(data.keys()) if isinstance(data, dict) else None
208
+ }
209
+
210
+ @app.post("/echo/text", tags=["POST Examples"])
211
+ async def echo_text(request: Request):
212
+ """POST - Echo back raw text body"""
213
+ body = await request.body()
214
+ return {
215
+ "received": body.decode("utf-8"),
216
+ "length": len(body),
217
+ "content_type": request.headers.get("content-type", "not specified")
218
+ }
219
+
220
+ # ============================================================================
221
+ # DIFFERENT RESPONSE FORMATS
222
+ # ============================================================================
223
+
224
+ @app.get("/format/json", tags=["Response Formats"])
225
+ def format_json():
226
+ """Returns data as JSON (default)"""
227
+ return {
228
+ "format": "JSON",
229
+ "content_type": "application/json",
230
+ "data": {"name": "Alice", "age": 30, "city": "Mumbai"}
231
+ }
232
+
233
+ @app.get("/format/text", response_class=PlainTextResponse, tags=["Response Formats"])
234
+ def format_text():
235
+ """Returns data as plain text"""
236
+ return """Format: Plain Text
237
+ Content-Type: text/plain
238
+
239
+ Name: Alice
240
+ Age: 30
241
+ City: Mumbai
242
+
243
+ This is plain text - no special formatting!"""
244
+
245
+ @app.get("/format/html", response_class=HTMLResponse, tags=["Response Formats"])
246
+ def format_html():
247
+ """Returns data as HTML"""
248
+ return """
249
+ <!DOCTYPE html>
250
+ <html>
251
+ <head>
252
+ <title>HTML Response</title>
253
+ <style>
254
+ body { font-family: Arial, sans-serif; padding: 20px; }
255
+ .card { border: 1px solid #ddd; padding: 15px; border-radius: 8px; max-width: 300px; }
256
+ h1 { color: #333; }
257
+ </style>
258
+ </head>
259
+ <body>
260
+ <h1>HTML Response Example</h1>
261
+ <div class="card">
262
+ <h2>User Info</h2>
263
+ <p><strong>Name:</strong> Alice</p>
264
+ <p><strong>Age:</strong> 30</p>
265
+ <p><strong>City:</strong> Mumbai</p>
266
+ </div>
267
+ <p><em>Content-Type: text/html</em></p>
268
+ </body>
269
+ </html>
270
+ """
271
+
272
+ @app.get("/format/xml", tags=["Response Formats"])
273
+ def format_xml():
274
+ """Returns data as XML"""
275
+ xml_content = """<?xml version="1.0" encoding="UTF-8"?>
276
+ <response>
277
+ <format>XML</format>
278
+ <content_type>application/xml</content_type>
279
+ <data>
280
+ <user>
281
+ <name>Alice</name>
282
+ <age>30</age>
283
+ <city>Mumbai</city>
284
+ </user>
285
+ </data>
286
+ </response>"""
287
+ return Response(content=xml_content, media_type="application/xml")
288
+
289
+ # ============================================================================
290
+ # EDUCATIONAL ENDPOINTS
291
+ # ============================================================================
292
+
293
+ @app.get("/headers", tags=["Educational"])
294
+ def show_headers(request: Request):
295
+ """Shows all request headers sent by the client"""
296
+ headers_dict = dict(request.headers)
297
+ return {
298
+ "your_headers": headers_dict,
299
+ "common_headers_explained": {
300
+ "user-agent": "Identifies your browser/client",
301
+ "accept": "What content types you accept",
302
+ "host": "The server you're connecting to",
303
+ "content-type": "Format of data you're sending (for POST/PUT)"
304
+ }
305
+ }
306
+
307
+ @app.get("/headers/custom", tags=["Educational"])
308
+ def custom_header_response():
309
+ """Returns a response with custom headers"""
310
+ content = {"message": "Check the response headers!"}
311
+ headers = {
312
+ "X-Custom-Header": "Hello from the server!",
313
+ "X-Request-Time": datetime.now().isoformat(),
314
+ "X-API-Version": "1.0.0"
315
+ }
316
+ return JSONResponse(content=content, headers=headers)
317
+
318
+ @app.get("/status/{code}", tags=["Educational"])
319
+ def return_status_code(
320
+ code: int = Path(..., description="HTTP status code to return (100-599)")
321
+ ):
322
+ """Returns the specified HTTP status code - useful for testing error handling"""
323
+ status_messages = {
324
+ 200: "OK - Request succeeded",
325
+ 201: "Created - Resource created successfully",
326
+ 204: "No Content - Success but no content to return",
327
+ 400: "Bad Request - Invalid request syntax",
328
+ 401: "Unauthorized - Authentication required",
329
+ 403: "Forbidden - Access denied",
330
+ 404: "Not Found - Resource doesn't exist",
331
+ 405: "Method Not Allowed - Wrong HTTP method",
332
+ 500: "Internal Server Error - Server error",
333
+ 502: "Bad Gateway - Invalid response from upstream",
334
+ 503: "Service Unavailable - Server temporarily unavailable",
335
+ }
336
+
337
+ if code < 100 or code > 599:
338
+ raise HTTPException(status_code=400, detail="Status code must be between 100 and 599")
339
+
340
+ message = status_messages.get(code, f"Status code {code}")
341
+
342
+ if code >= 400:
343
+ raise HTTPException(status_code=code, detail=message)
344
+
345
+ return JSONResponse(
346
+ status_code=code,
347
+ content={"status_code": code, "message": message}
348
+ )
349
+
350
+ @app.api_route("/method", methods=["GET", "POST", "PUT", "DELETE", "PATCH"], tags=["Educational"])
351
+ async def show_method(request: Request):
352
+ """Accepts any HTTP method and shows what was used"""
353
+ body = None
354
+ if request.method in ["POST", "PUT", "PATCH"]:
355
+ try:
356
+ body = await request.json()
357
+ except:
358
+ body = (await request.body()).decode("utf-8") or None
359
+
360
+ return {
361
+ "method_used": request.method,
362
+ "method_explanation": {
363
+ "GET": "Retrieve data (no body)",
364
+ "POST": "Create new resource (has body)",
365
+ "PUT": "Replace entire resource (has body)",
366
+ "PATCH": "Partial update (has body)",
367
+ "DELETE": "Remove resource (usually no body)"
368
+ }.get(request.method, "Unknown method"),
369
+ "body_received": body,
370
+ "url": str(request.url),
371
+ "query_params": dict(request.query_params)
372
+ }
373
+
374
+ @app.get("/ip", tags=["Educational"])
375
+ def get_client_ip(request: Request):
376
+ """Returns the client's IP address"""
377
+ forwarded = request.headers.get("x-forwarded-for")
378
+ if forwarded:
379
+ ip = forwarded.split(",")[0].strip()
380
+ else:
381
+ ip = request.client.host if request.client else "unknown"
382
+
383
+ return {
384
+ "ip": ip,
385
+ "note": "Behind a proxy, this shows the proxy's IP unless X-Forwarded-For is set"
386
+ }
387
+
388
+ # ============================================================================
389
+ # QUERY PARAMETER TYPES
390
+ # ============================================================================
391
+
392
+ @app.get("/params/types", tags=["Parameter Examples"])
393
+ def parameter_types(
394
+ string_param: str = Query(default="hello", description="A string parameter"),
395
+ int_param: int = Query(default=42, description="An integer parameter"),
396
+ float_param: float = Query(default=3.14, description="A float parameter"),
397
+ bool_param: bool = Query(default=True, description="A boolean parameter"),
398
+ list_param: List[str] = Query(default=["a", "b"], description="A list parameter")
399
+ ):
400
+ """Demonstrates different query parameter types"""
401
+ return {
402
+ "parameters_received": {
403
+ "string_param": {"value": string_param, "type": "str"},
404
+ "int_param": {"value": int_param, "type": "int"},
405
+ "float_param": {"value": float_param, "type": "float"},
406
+ "bool_param": {"value": bool_param, "type": "bool"},
407
+ "list_param": {"value": list_param, "type": "list"}
408
+ },
409
+ "example_url": "/params/types?string_param=test&int_param=100&float_param=2.5&bool_param=false&list_param=x&list_param=y"
410
+ }
411
+
412
+ # ============================================================================
413
+ # RUN SERVER (for local development)
414
+ # ============================================================================
415
+
416
+ if __name__ == "__main__":
417
+ import uvicorn
418
+ uvicorn.run(app, host="0.0.0.0", port=7860)
requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ fastapi>=0.104.0
2
+ uvicorn[standard]>=0.24.0
3
+ pydantic>=2.0.0