33import nanoid
44from appwrite .services .databases import Databases
55from appwrite .query import Query
6+ from appwrite .exceptions import AppwriteException
67from . 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 )
0 commit comments