{"id":16841387,"url":"https://github.com/thebeanogamer/linkshortener","last_synced_at":"2026-06-28T05:32:02.800Z","repository":{"id":37086841,"uuid":"229780178","full_name":"thebeanogamer/linkshortener","owner":"thebeanogamer","description":"An over-engineered AWS Link Shortener","archived":false,"fork":false,"pushed_at":"2023-03-06T14:58:19.000Z","size":978,"stargazers_count":1,"open_issues_count":23,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-09-03T06:37:39.818Z","etag":null,"topics":["aws","aws-lambda","hacktoberfest","serverless-framework"],"latest_commit_sha":null,"homepage":"https://beano.dev","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/thebeanogamer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-23T15:42:06.000Z","updated_at":"2022-05-19T14:37:10.000Z","dependencies_parsed_at":"2025-04-05T10:37:02.812Z","dependency_job_id":null,"html_url":"https://github.com/thebeanogamer/linkshortener","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/thebeanogamer/linkshortener","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thebeanogamer%2Flinkshortener","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thebeanogamer%2Flinkshortener/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thebeanogamer%2Flinkshortener/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thebeanogamer%2Flinkshortener/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/thebeanogamer","download_url":"https://codeload.github.com/thebeanogamer/linkshortener/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/thebeanogamer%2Flinkshortener/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34878963,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","aws-lambda","hacktoberfest","serverless-framework"],"created_at":"2024-10-13T12:41:44.104Z","updated_at":"2026-06-28T05:32:02.785Z","avatar_url":"https://github.com/thebeanogamer.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Link Shortener\n\n[![Build Status](https://dev.azure.com/thebeanogamer/linkshortener/_apis/build/status/Validate%20Pipeline?branchName=master)](https://dev.azure.com/thebeanogamer/linkshortener/_build/latest?definitionId=5\u0026branchName=master) [![Build Status](https://dev.azure.com/thebeanogamer/linkshortener/_apis/build/status/Deploy%20Pipeline?branchName=master)](https://dev.azure.com/thebeanogamer/linkshortener/_build/latest?definitionId=6\u0026branchName=master) ![Licence](https://img.shields.io/github/license/thebeanogamer/linkshortener) ![Python 3.8.x](https://img.shields.io/badge/python-3.8.x-yellow.svg)\n\nThis project is an over-engineered Link Shortener built using as many AWS services as was reasonably possible. An example deployment of this is available on \u003chttps://beano.dev\u003e.\n\n## Usage\n\n### Deploy\n\nBefore running the deployment, you must manually create a certificate for your domain in `us-east-1` and configure SES and Route 53 in a region of your choice. Unless you request a usage limit increase from AWS, you will need to manually [verify your email](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/sending-authorization-identity-owner-tasks-verification.html) within SES. You will also need to set the following environment variables on the deploying machine.\n\nVariable | Value\n--- | ---\n`ADMIN_CONTACT` | The email address for updates to be sent to\n`DOMAIN` | The domain your shortener will be hosted on\n`FALLBACK_URL` | The URL to redirect to in the absence of a specifically defined one\n`AWS_REGION` | The region to deploy to\n`SES_REGION` | The region where you have configured SES\n\n```bash\nnpm install\nserverless create_domain --stage prod # This only needs to be run once but may take up to 40 mins\nserverless deploy --stage prod\n```\n\n### Database\n\nThe database used is DynamoDB, below can be seen an example record which would redirect from `/blog` to `https://blog.daniel-milnes.uk`.\n\n```json\n{\n  \"code\": \"blog\",\n  \"url\": \"https://blog.daniel-milnes.uk\",\n  \"uses\": {\n    \"lifetime\": 0,\n    \"recent\": 0\n  }\n}\n```\n\n### Emails\n\nLink Shortener tracks two values for usage, `lifetime` and `recent`. The `recent` key is cleared every time a usage summary is generated. A summary will be sent to the email defined in the `ADMIN_CONTACT` environment variable every 24 hours when there has been use, or when an authorized user POSTs to `/email`. The email can also be previewed on `/email`.\n\n## System Diagrams\n\n### Deployment\n\n![Deployment Pipeline](assets/Deploy.svg)\n\n### Shortener\n\n![Usage Pipeline](assets/Usage.svg)\n\n### Email\n\n![Email Pipeline](assets/Email.svg)\n\n## Endpoints\n\nEndpoints with the 🔑 emoji require the `X-Api-Key` header.\n\n### GET - `/`\n\nRedirect to the url defined in `FALLBACK_URL`.\n\n### GET - `/{id}`\n\nFollow a redirect rule. If no rule for the URL requested is found, a redirect to `FALLBACK_URL` will be sent.\n\n### GET - `/manage` 🔑\n\nGet information about a redirect route. If the `code=` parameter is not included or has no value, details about all routes will be shown.\n\n### PUT - `/manage` 🔑\n\nCreate a redirect route.\n\n#### Request body\n\n```json\n{\n    \"code\": \"\",\n    \"url\": \"\"\n}\n```\n\n### DELETE - `/manage` 🔑\n\nDelete a redirect route.\n\n#### Request body\n\n```json\n{\n    \"code\": \"\"\n}\n```\n\n### GET - `/email` 🔑\n\nPreview the summary email.\n\n### POST - `/email` 🔑\n\nTrigger a summary email.\n\n### GET - `/robots.txt`\n\nTo prevent search engines trying to crawl the link shortener.\n\n```yaml\nUser-agent: *\nDisallow: /\n```\n\n### GET - `/favicon.ico`\n\nReturns 404 to prevent the browser trying to load the favicon and being redirected to `FALLBACK_URL`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthebeanogamer%2Flinkshortener","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthebeanogamer%2Flinkshortener","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthebeanogamer%2Flinkshortener/lists"}