-
Notifications
You must be signed in to change notification settings - Fork 121
feat: Add Python URL shortener template #341
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
trivedikavya
wants to merge
4
commits into
appwrite:main
Choose a base branch
from
trivedikavya:feat-python-url-shortener
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e29a0be
feat: Add Python URL shortener template
trivedikavya 8ebb5c1
fix: Apply suggestions from code review
trivedikavya 547490f
feat: Address all review feedback from coderabbitai
trivedikavya 3727d00
fix: Handle non-collision errors during ID generation
trivedikavya File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| # URL Shortener in Python | ||
|
|
||
| A Python function to create and manage short URLs. | ||
|
|
||
| ## 📝 Environment Variables | ||
|
|
||
| - `APPWRITE_ENDPOINT`: Your Appwrite endpoint. | ||
| - `APPWRITE_API_KEY`: Your Appwrite API key. | ||
| - `APPWRITE_PROJECT`: Your Appwrite project ID. | ||
| - `DATABASE_ID`: The ID of the database to store URLs. | ||
| - `COLLECTION_ID`: The ID of the collection to store URLs. | ||
|
|
||
| ## 🚀 Building and Deployment | ||
|
|
||
| 1. **Create an Appwrite Database and Collection:** | ||
| * Create a database with a unique ID. | ||
| * Create a collection with the following attribute: | ||
| * `original_url` (string, required) | ||
|
|
||
| 2. **Deploy the Function:** | ||
| * Package the function: `tar -czvf code.tar.gz .` | ||
| * Upload and deploy the packaged function to your Appwrite project. | ||
|
|
||
| ## 🛠️ Usage | ||
|
|
||
| ### Create a Short URL | ||
|
|
||
| Execute the function with the following JSON data to create a short URL: | ||
|
|
||
| ```json | ||
| { | ||
| "url": "https://www.google.com" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| appwrite==3.1.0 | ||
| nanoid==2.0.0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| import os | ||
| import json | ||
| import nanoid | ||
| from appwrite.services.databases import Databases | ||
| from appwrite.query import Query | ||
| from appwrite.exceptions import AppwriteException | ||
| from . import utils | ||
|
|
||
| # This is your Appwrite function | ||
| # It's executed each time we get a request | ||
| def main(context): | ||
| # Get Appwrite's database client | ||
| database = utils.get_database() | ||
|
|
||
| # --- (Suggestion 2) Validate Database Environment Variables --- | ||
| database_id = os.environ.get("DATABASE_ID") | ||
| collection_id = os.environ.get("COLLECTION_ID") | ||
|
|
||
| if not database_id or not collection_id: | ||
| return context.res.json( | ||
| {'error': 'Missing required environment variables: DATABASE_ID or COLLECTION_ID'}, | ||
| status_code=500 | ||
| ) | ||
|
|
||
| # --- (Suggestion 4, Part 1) Handle Redirection from URL Path --- | ||
| # Check for short_id in the path, e.g. /v1/functions/.../executions/.../6aT8bC1 | ||
| path_parts = context.req.path.split('/') | ||
| short_id_from_path = path_parts[-1] if len(path_parts) > 1 and len(path_parts[-1]) == 7 else None | ||
|
|
||
| if context.req.method == 'GET' and short_id_from_path: | ||
| try: | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| result = database.list_documents( | ||
| database_id, | ||
| collection_id, | ||
| [Query.equal("$id", short_id_from_path)] | ||
| ) | ||
| if result['total'] > 0: | ||
| original_url = result['documents'][0]['original_url'] | ||
| return context.res.redirect(original_url, 301) | ||
| else: | ||
| return context.res.json({'error': 'URL not found'}, status_code=404) | ||
| # --- (Suggestion 5) Specific Exception Handling --- | ||
| except AppwriteException as e: | ||
| return context.res.json({'error': str(e)}, status_code=500) | ||
|
|
||
| # --- (Suggestion 1) Handle JSON Parsing Errors --- | ||
| try: | ||
| payload = json.loads(context.req.body) if context.req.body else {} | ||
| except json.JSONDecodeError: | ||
| return context.res.json({'error': 'Invalid JSON payload'}, status_code=400) | ||
|
|
||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| # --- Action: Create a short URL --- | ||
| if 'url' in payload: | ||
| original_url = payload['url'] | ||
|
|
||
| # --- (Suggestion 3) Add URL Validation --- | ||
| if not original_url or not isinstance(original_url, str): | ||
| return context.res.json({'error': 'Invalid URL format'}, status_code=400) | ||
| if len(original_url) > 2048: | ||
| return context.res.json({'error': 'URL too long (max 2048 characters)'}, status_code=400) | ||
| if not original_url.startswith(('http://', 'https://')): | ||
| return context.res.json({'error': 'URL must start with http:// or https://'}, status_code=400) | ||
|
|
||
| short_id = nanoid.generate(size=7) | ||
|
|
||
| try: | ||
| database.create_document( | ||
| database_id, | ||
| collection_id, | ||
| short_id, | ||
| {'original_url': original_url} | ||
| ) | ||
| # --- (Suggestion 4, Part 2) Construct Correct short_url --- | ||
| # It should point to the function itself | ||
| execution_path = context.req.path | ||
| short_url = f"{context.req.scheme}://{context.req.host}{execution_path}/{short_id}" | ||
| return context.res.json({'short_url': short_url}) | ||
| # --- (Suggestion 5) Specific Exception Handling --- | ||
| except AppwriteException as e: | ||
| return context.res.json({'error': str(e)}, status_code=500) | ||
|
|
||
| return context.res.json({'error': 'Invalid request. Provide a "url" in the JSON body to shorten.'}, status_code=400) | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import os | ||
| from appwrite.client import Client | ||
| from appwrite.services.databases import Databases | ||
|
|
||
| # This is your Appwrite function | ||
| # It's executed each time we get a request | ||
| def get_database(): | ||
| # Validate environment variables | ||
| required_vars = ["APPWRITE_ENDPOINT", "APPWRITE_PROJECT", "APPWRITE_API_KEY"] | ||
| missing_vars = [var for var in required_vars if var not in os.environ] | ||
| if missing_vars: | ||
| raise ValueError(f"Missing required environment variables: {', '.join(missing_vars)}") | ||
|
|
||
| # Initialize the Appwrite client | ||
| client = Client() | ||
| client.set_endpoint(os.environ["APPWRITE_ENDPOINT"]) | ||
| client.set_project(os.environ["APPWRITE_PROJECT"]) | ||
| client.set_key(os.environ["APPWRITE_API_KEY"]) | ||
|
|
||
| # Initialize the database service | ||
| return Databases(client) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.