{"id":23114122,"url":"https://github.com/jcserv/vu-mi","last_synced_at":"2025-04-04T00:27:11.842Z","repository":{"id":252311479,"uuid":"838562288","full_name":"jcserv/vu-mi","owner":"jcserv","description":"A very over-engineered serverless application enabling users to add visitor count badges to their Github profile.","archived":false,"fork":false,"pushed_at":"2024-08-11T22:30:03.000Z","size":15237,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-02-09T12:28:31.428Z","etag":null,"topics":["aws","dynamodb","dynamodb-streams","serverless","sqs"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jcserv.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":"2024-08-05T22:48:03.000Z","updated_at":"2024-08-11T22:30:06.000Z","dependencies_parsed_at":"2024-08-11T22:42:25.335Z","dependency_job_id":null,"html_url":"https://github.com/jcserv/vu-mi","commit_stats":null,"previous_names":["jcserv/vu-mi"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jcserv%2Fvu-mi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jcserv%2Fvu-mi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jcserv%2Fvu-mi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jcserv%2Fvu-mi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jcserv","download_url":"https://codeload.github.com/jcserv/vu-mi/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247101228,"owners_count":20883739,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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","dynamodb","dynamodb-streams","serverless","sqs"],"created_at":"2024-12-17T03:19:22.860Z","updated_at":"2025-04-04T00:27:11.825Z","avatar_url":"https://github.com/jcserv.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vu-mi\n\nvu-mi is a public API to enable view count badges in Markdown. \nThe API returns up-to-date counts, up to {prevComputedCount} + 7999. Any more than that, and it will show a stale count.\n\n\nIt is tremendously over-engineered, using the following technologies:\n- AWS Lambda\n- DynamoDB\n- DynamoDB Streams\n- SQS\n\nI did it to implement concepts I've learned about, but never worked with such as:\n- Modelling one-to-many relationships in a DynamoDB single table design (from [The DynamoDB Book](https://dynamodbbook.com/), by Alex Debrie)\n- Change Data Capture\n\n## Usage\n\nTo use this in a Markdown document, simply paste the following, and insert your unique ID:\n```md\n![visitors](https://img.shields.io/endpoint?url=https://vu-mi.com/api/v1/views?id=\u003cINSERT_UNIQUE_ID_HERE\u003e)\n```\n\n![visitors](https://img.shields.io/endpoint?url=https://vu-mi.com/api/v1/views?id=jcserv/vu-mi)\n\nThe ID could be your Github username, Github repo, anything you want really.\n\n## API\n\n### GET /v1/api/views?id=YOUR-ID-HERE\nResponse:\n```\n200 OK\n{\n    \"schemaVersion\": 1,\n    \"label\": \"views\",\n    \"message\": \"12\",\n    \"color\": \"blue\"\n}\n```\n\n## Design\n\n### End-to-End Flow\n\n![system-diagram](docs/system-diagram.jpg)\n\n`\u003cget-views-lambda\u003e`\n1. `GET /v1/api/views?id=jcserv` request comes into `get-views-lambda`\n2. `get-views-lambda` queries Dynamo for all items with matching PK, limit of 8000\n3.  a. Send SQS message with user id \u0026 count\n\n    b. Return response with count - 1 (minus one to account for the USER item)\n\n`\u003cput-views-lambda\u003e`\n\n4. If the provided count is 0, PUT the USER item\n\u003e Q: Is there a risk of race conditions here when multiple requests come in for a new user?\n\nA: There is, if the message to the `put-views-lambda` comes after a `batch-update-count-lambda` invocation, it can override the count to 0.\nTo circumvent this, we only PUT the user item IFF the user object does not already exist (\"attribute_not_exists(PK) AND attribute_not_exists(SK)\")\n\n5. Put VIEW item, with TTL rounded to the next 5 min interval\n\n6. Items expire; DynamoDB streams sends records with each item\n\n\u003e This is essentially the same as having a 5-min cron job to collate View items, but without having to SCAN the entire table.\n\n\u003e Streams is also nice here since, rather than one invocation per item expiring, we can do a bulk update. Savings++\n\n`\u003cbatch-update-count-lambda\u003e`\n\n7. Get the user object using the PK provided from the DynamoDB Streams record\n\n8. Put the new count onto the user item\n\n### Dynamo Model\n\n![dynamo-model](docs/dynamo-model.png)\n\n## Discussion\n\n\u003e Q: Was this really necessary?\n\nNot really, it could've been achieved with a simpler design, like so:\n\n![system-diagram-v1](docs/system-diagram-v1.jpg)\n\nBut that wouldn't be fun!\n\n## Author's Note\n\nThis project is named after my cat Yumi, since I implemented the majority of this during an early morning\nafter she woke me up TT\n\n\u003cimg src=\"docs/yumi.png\" alt=\"drawing\" width=\"400\"/\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjcserv%2Fvu-mi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjcserv%2Fvu-mi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjcserv%2Fvu-mi/lists"}