Skip to content

Commit 8ebb5c1

Browse files
committed
fix: Apply suggestions from code review
1 parent e29a0be commit 8ebb5c1

3 files changed

Lines changed: 58 additions & 30 deletions

File tree

python/url-shortener/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ Execute the function with the following JSON data to create a short URL:
2929

3030
```json
3131
{
32-
"url": "[https://www.google.com](https://www.google.com)"
32+
"url": "https://www.google.com"
3333
}

python/url-shortener/src/main.py

Lines changed: 51 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import nanoid
44
from appwrite.services.databases import Databases
55
from appwrite.query import Query
6+
from appwrite.exceptions import AppwriteException
67
from . import utils
78

89
# This is your Appwrite function
@@ -11,50 +12,71 @@ def main(context):
1112
# Get Appwrite's database client
1213
database = utils.get_database()
1314

14-
# Database and collection IDs
15+
# --- (Suggestion 2) Validate Database Environment Variables ---
1516
database_id = os.environ.get("DATABASE_ID")
1617
collection_id = os.environ.get("COLLECTION_ID")
1718

18-
# The payload will contain 'url' to shorten or 'short_id' to redirect
19-
payload = json.loads(context.req.body)
19+
if not database_id or not collection_id:
20+
return context.res.json(
21+
{'error': 'Missing required environment variables: DATABASE_ID or COLLECTION_ID'},
22+
status_code=500
23+
)
2024

21-
# Action: Create a short URL
22-
if 'url' in payload:
23-
original_url = payload['url']
24-
short_id = nanoid.generate(size=7)
25-
26-
try:
27-
database.create_document(
28-
database_id,
29-
collection_id,
30-
short_id,
31-
{'original_url': original_url}
32-
)
33-
short_url = f"{context.req.scheme}://{context.req.host}/v1/databases/{database_id}/collections/{collection_id}/documents/{short_id}"
34-
return context.res.json({'short_url': short_url})
35-
except Exception as e:
36-
return context.res.json({'error': str(e)}, status_code=500)
37-
38-
# Action: Redirect to the original URL
39-
if 'short_id' in payload:
40-
short_id = payload['short_id']
25+
# --- (Suggestion 4, Part 1) Handle Redirection from URL Path ---
26+
# Check for short_id in the path, e.g. /v1/functions/.../executions/.../6aT8bC1
27+
path_parts = context.req.path.split('/')
28+
short_id_from_path = path_parts[-1] if len(path_parts) > 1 and len(path_parts[-1]) == 7 else None
4129

30+
if context.req.method == 'GET' and short_id_from_path:
4231
try:
43-
# Find the document with the given short_id
4432
result = database.list_documents(
4533
database_id,
4634
collection_id,
47-
[Query.equal("$id", short_id)]
35+
[Query.equal("$id", short_id_from_path)]
4836
)
49-
5037
if result['total'] > 0:
5138
original_url = result['documents'][0]['original_url']
5239
return context.res.redirect(original_url, 301)
5340
else:
5441
return context.res.json({'error': 'URL not found'}, status_code=404)
42+
# --- (Suggestion 5) Specific Exception Handling ---
43+
except AppwriteException as e:
44+
return context.res.json({'error': str(e)}, status_code=500)
5545

56-
except Exception as e:
46+
# --- (Suggestion 1) Handle JSON Parsing Errors ---
47+
try:
48+
payload = json.loads(context.req.body) if context.req.body else {}
49+
except json.JSONDecodeError:
50+
return context.res.json({'error': 'Invalid JSON payload'}, status_code=400)
51+
52+
# --- Action: Create a short URL ---
53+
if 'url' in payload:
54+
original_url = payload['url']
55+
56+
# --- (Suggestion 3) Add URL Validation ---
57+
if not original_url or not isinstance(original_url, str):
58+
return context.res.json({'error': 'Invalid URL format'}, status_code=400)
59+
if len(original_url) > 2048:
60+
return context.res.json({'error': 'URL too long (max 2048 characters)'}, status_code=400)
61+
if not original_url.startswith(('http://', 'https://')):
62+
return context.res.json({'error': 'URL must start with http:// or https://'}, status_code=400)
63+
64+
short_id = nanoid.generate(size=7)
65+
66+
try:
67+
database.create_document(
68+
database_id,
69+
collection_id,
70+
short_id,
71+
{'original_url': original_url}
72+
)
73+
# --- (Suggestion 4, Part 2) Construct Correct short_url ---
74+
# It should point to the function itself
75+
execution_path = context.req.path
76+
short_url = f"{context.req.scheme}://{context.req.host}{execution_path}/{short_id}"
77+
return context.res.json({'short_url': short_url})
78+
# --- (Suggestion 5) Specific Exception Handling ---
79+
except AppwriteException as e:
5780
return context.res.json({'error': str(e)}, status_code=500)
5881

59-
# If no valid action is found
60-
return context.res.json({'error': 'Invalid request. Provide either a "url" or a "short_id".'}, status_code=400)
82+
return context.res.json({'error': 'Invalid request. Provide a "url" in the JSON body to shorten.'}, status_code=400)

python/url-shortener/src/utils.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@
55
# This is your Appwrite function
66
# It's executed each time we get a request
77
def get_database():
8+
# Validate environment variables
9+
required_vars = ["APPWRITE_ENDPOINT", "APPWRITE_PROJECT", "APPWRITE_API_KEY"]
10+
missing_vars = [var for var in required_vars if var not in os.environ]
11+
if missing_vars:
12+
raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}")
13+
814
# Initialize the Appwrite client
915
client = Client()
1016
client.set_endpoint(os.environ["APPWRITE_ENDPOINT"])

0 commit comments

Comments
 (0)