{"id":20107099,"url":"https://github.com/juliojimenez/hypermedia.systems","last_synced_at":"2025-05-06T09:32:26.381Z","repository":{"id":187328472,"uuid":"676361458","full_name":"juliojimenez/hypermedia.systems","owner":"juliojimenez","description":"Examples from the book Hypermedia Systems.","archived":false,"fork":false,"pushed_at":"2024-07-22T22:57:54.000Z","size":592,"stargazers_count":22,"open_issues_count":5,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-07-23T02:29:33.874Z","etag":null,"topics":["flask","htmx","hypermedia","hyperview","mypy","pytest","python","python3"],"latest_commit_sha":null,"homepage":"https://hypermedia.systems","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/juliojimenez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"juliojimenez","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2023-08-09T03:15:27.000Z","updated_at":"2024-07-04T13:40:21.000Z","dependencies_parsed_at":"2023-10-05T06:38:50.802Z","dependency_job_id":"7aaea620-2366-44d5-a6d9-0808951e4ae1","html_url":"https://github.com/juliojimenez/hypermedia.systems","commit_stats":null,"previous_names":["juliojimenez/hypermedia.systems"],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliojimenez%2Fhypermedia.systems","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliojimenez%2Fhypermedia.systems/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliojimenez%2Fhypermedia.systems/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/juliojimenez%2Fhypermedia.systems/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/juliojimenez","download_url":"https://codeload.github.com/juliojimenez/hypermedia.systems/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224500009,"owners_count":17321605,"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":["flask","htmx","hypermedia","hyperview","mypy","pytest","python","python3"],"created_at":"2024-11-13T17:55:48.174Z","updated_at":"2024-11-13T17:55:48.667Z","avatar_url":"https://github.com/juliojimenez.png","language":"Python","funding_links":["https://github.com/sponsors/juliojimenez"],"categories":[],"sub_categories":[],"readme":"# hypermedia.systems\n\n[![Type Checker](https://github.com/juliojimenez/hypermedia.systems/actions/workflows/typechecker.yml/badge.svg)](https://github.com/juliojimenez/hypermedia.systems/actions/workflows/typechecker.yml) [![Tests](https://github.com/juliojimenez/hypermedia.systems/actions/workflows/tests.yml/badge.svg)](https://github.com/juliojimenez/hypermedia.systems/actions/workflows/tests.yml)\n\nExamples from building the Contacts app in the book [Hypermedia Systems](https://hypermedia.systems).\n\nThe code here is slightly different from the book, as I try to use types where I can, and check for them using [Mypy](https://mypy.readthedocs.io/en/stable/index.html), a static type checker for Python.\n\n[PyTest](https://docs.pytest.org/en/7.4.x/) is used for testing. While inside an example directory simply run `pytest` to run the tests for that example.\n\n## Running an Example\n\nClone the repo...\n```bash\ngit clone https://github.com/juliojimenez/hypermedia.systems\ncd hypermedia.systems\n```\nInstall dependencies...\n```bash\npip3 install -r requirements.txt\n```\nGo to an example...\n```bash\ncd chapter-3/1-simple-hello-world/\n```\nAnd run it...\n```bash\npython3 app.py\n```\n\nEach example runs on a different port. Run multiple examples simultaneously and compare them in the browser!\n\n## Examples\n\n### Chapter 3\n\n- [Simple Hello World](./chapter-3/1-simple-hello-world/)\n- [Simple Hello World to a Redirect](./chapter-3/2-simple-hello-world-to-a-redirect/)\n- [Showing a Searchable List of Contacts](./chapter-3/3-showing-a-searchable-list-of-contacts/)\n- [Adding a New Contact](./chapter-3/4-adding-a-new-contact/)\n- [Viewing the Details of a Contact](./chapter-3/5-viewing-the-details-of-a-contact/)\n- [Editing a Contact](./chapter-3/6-editing-a-contact/)\n- [Deleting a Contact](./chapter-3/7-deleting-a-contact/)\n\n### Chapter 4\n\n- [Installing HTMX as a Third Party Dependency](./chapter-4/1-installing-htmx-third-party/)\n- [Triggering HTTP Requests](./chapter-4/2-triggering-http-requests/)\n- [HTMX vs. Plain HTML Responses](./chapter-4/3-htmx-vs-plain-html-responses/)\n- [Targeting Other Elements](./chapter-4/4-targeting-other-elements/)\n- [Swap Styles](./chapter-4/5-swap-styles/)\n- Using Events\n    - [mouseenter](./chapter-4/6-using-events-mouseenter/)\n    - [click and keyup](./chapter-4/7-using-events-click-and-keyup/)\n- Passing Request Parameters\n    - [Enclosing Forms](./chapter-4/8-passing-request-parameters-enclosing-forms/)\n    - [Including Inputs](./chapter-4/9-passing-request-parameters-including-inputs/)\n    - [Inline Values](./chapter-4/10-passing-request-parameters-inline-values/)\n- [History Support](./chapter-4/11-history-support/)\n\n### Chapter 5\n\n- [Installing HTMX as a Vendored Dependency](./chapter-5/1-installing-htmx-vendored/)\n- [Adding hx-boost to Contacts.app](./chapter-5/2-adding-hx-boost-to-contact-app/)\n- [A Second Step: Deleting Contacts With HTTP DELETE](./chapter-5/3-a-second-step-deleting-contacts-with-http-delete/)\n- Next Steps: Validating Contact Emails\n    - [Update Our Input Type](./chapter-5/4-next-steps-validating-contact-emails-update-our-input-type/)\n    - [Inline Validation](./chapter-5/5-next-steps-validating-contact-emails-inline-validation/)\n    - [Validating Emails Server-Side](./chapter-5/6-next-steps-validating-contact-emails-validating-emails-server-side/)\n    - [Taking The User Experience Further](./chapter-5/7-next-steps-validating-contact-emails-taking-the-user-experience-further/)\n    - [Debouncing Our Validation Requests](./chapter-5/8-next-steps-validating-contact-emails-debouncing-our-validation-requests/)\n    - [Ignoring Non-Mutating Keys](./chapter-5/9-next-steps-validating-contact-emails-ignoring-non-mutating-keys/)\n- Another Application Improvement: Paging\n    - [Adding Paging Widgets](./chapter-5/10-another-application-improvement-paging-adding-paging-widgets/)\n    - [Click To Load](./chapter-5/11-another-application-improvement-paging-click-to-load/)\n    - [Infinite Scroll](./chapter-5/12-another-application-improvement-paging-infinite-scroll/)\n\n### Chapter 6\n\n- [Adding Active Search](./chapter-6/1-adding-active-search/)\n    - [Targeting The Correct Element](./chapter-6/2-targeting-the-correct-element/)\n    - [Paring Down Our Content](./chapter-6/3-paring-down-our-content/)\n    - [HTTP Headers In HTMX](./chapter-6/4-http-headers-in-htmx/)\n    - [Factoring Your Templates](./chapter-6/4-http-headers-in-htmx/)\n    - [Using Our New Template](./chapter-6/4-http-headers-in-htmx/)\n    - [Updating The Navigation Bar With \"hx-push-url\"](./chapter-6/5-updating-the-navigation-bar-with-hx-push-url/)\n    - [Adding A Request Indicator](./chapter-6/6-adding-a-request-indicator/)\n- [Lazy Loading](./chapter-6/7-lazy-loading/)\n    - [Pulling Out The Expensive Code](./chapter-6/8-pulling-out-the-expensive-code/)\n    - [Adding An Indicator](./chapter-6/9-adding-an-indicator/)\n    - [But That's Not Lazy!](./chapter-6/10-but-thats-not-lazy/)\n- [Inline Delete](./chapter-6/11-inline-delete/)\n    - [Narrowing Our Target](./chapter-6/12-narrowing-our-target/)\n    - [Updating The Server Side](./chapter-6/13-updating-the-server-side/)\n    - [Taking Advantage of \"htmx-swapping\"](./chapter-6/14-taking-advantage-of-htmx-swapping/)\n- [Bulk Delete](./chapter-6/15-bulk-delete/)\n    - [The \"Delete Selected Contacts\" Button](./chapter-6/16-the-delete-selected-contacts-button/)\n    - [The Server Side for Delete Selected Contacts](./chapter-6/17-the-server-side-for-delete-selected-contacts/)\n\n### Chapter 7\n\n- [Beginning Our Implementation](./chapter-7/1-beginning-our-implementation/)\n- [Adding The Archiving Endpoing](./chapter-7/2-adding-the-archiving-endpoint/)\n- [Conditionally Rendering A Progress UI](./chapter-7/3-conditionally-rendering-a-progress-ui/)\n- [Using Polling To Update The Archive UI](./chapter-7/4-using-polling-to-update-the-archive-ui/)\n- [Downloading The Result](./chapter-7/5-downloading-the-result/)\n- [Downloading The Completed Archive](./chapter-7/6-downloading-the-completed-archive/)\n- [Our Smoothing Solution](./chapter-7/7-our-smoothing-solution/)\n- [Dismissing The Download UI](./chapter-7/8-dismissing-the-download-ui/)\n- [An Alternative UX: Auto-Download](./chapter-7/9-an-alternative-ux-auto-download/)\n\n### Chapter 9\n\n- [VanillaJS in Action: An Overflow Menu](./chapter-9/1-vanillajs-in-action-an-overflow-menu)\n- [Alpine.js](./chapter-9/2-alpine.js)\n- [_hyperscript](./chapter-9/3-hyperscript)\n- [Integrating Using Callbacks](./chapter-9/4-integrating-using-callbacks)\n- [Integrating Using Events](./chapter-9/5-integrating-using-events)\n\n### Chapter 10\n\n- [Our First JSON Endpoint: Listing All Contacts](./chapter-10/1-listing-all-contacts)\n- [Adding Contacts](./chapter-10/2-adding-contacts)\n- [Viewing Contact Details](./chapter-10/3-viewing-contact-details)\n- [Updating \u0026 Deleting Contacts](./chapter-10/4-updating-and-deleting-contacts)\n\n## Support\n\nPython 3.11+\n\n## Dependencies\n\n- [HTMX v1.9.5](https://htmx.org)\n- [missing.css v1.0.10](https://missing.style)\n    - Not sure what's going on with the package hosting for this, but I had to grab the artifact from the latest tag in the [repo](https://github.com/bigskysoftware/missing).\n    - It was working fine when I started this repository. If it starts working again, please submit an issue or hit me up on [X](https://twitter.com/LispDev).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliojimenez%2Fhypermedia.systems","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjuliojimenez%2Fhypermedia.systems","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjuliojimenez%2Fhypermedia.systems/lists"}