{"id":13725013,"url":"https://github.com/healeycodes/jar","last_synced_at":"2025-07-02T11:38:14.690Z","repository":{"id":112378163,"uuid":"603446365","full_name":"healeycodes/jar","owner":"healeycodes","description":"🫙 A server-side web framework that deploys to Vercel.","archived":false,"fork":false,"pushed_at":"2024-11-18T15:10:51.000Z","size":90,"stargazers_count":33,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-30T18:45:00.685Z","etag":null,"topics":["build-output-api","serverless-functions","vercel","web-framework"],"latest_commit_sha":null,"homepage":"https://jar-docs.vercel.app","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/healeycodes.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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":"2023-02-18T14:41:00.000Z","updated_at":"2024-11-18T15:11:10.000Z","dependencies_parsed_at":"2024-12-10T16:37:40.622Z","dependency_job_id":null,"html_url":"https://github.com/healeycodes/jar","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/healeycodes/jar","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/healeycodes%2Fjar","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/healeycodes%2Fjar/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/healeycodes%2Fjar/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/healeycodes%2Fjar/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/healeycodes","download_url":"https://codeload.github.com/healeycodes/jar/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/healeycodes%2Fjar/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263131242,"owners_count":23418424,"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":["build-output-api","serverless-functions","vercel","web-framework"],"created_at":"2024-08-03T01:02:09.826Z","updated_at":"2025-07-02T11:38:14.632Z","avatar_url":"https://github.com/healeycodes.png","language":"Python","readme":"[![CI](https://github.com/healeycodes/jar/actions/workflows/ci.yml/badge.svg)](https://github.com/healeycodes/jar/actions/workflows/ci.yml)\n\n# Jar 🫙\n\u003e My blog post: [My Own Python Web Framework](https://healeycodes.com/my-own-python-web-framework)\n\n\u003cbr\u003e\n\nJar is a toy Python web framework, implemented in about 200 lines of code (see [cli.py](https://github.com/healeycodes/jar/blob/main/framework/cli.py)).\n\nI built it to explore some ideas around framework APIs. Please don't actually use it.\n\nIt deploys to Vercel via the [Build Output API](https://vercel.com/docs/build-output-api/v3). \n\nIt's called Jar because it has almost no features and you need to fill it up yourself!\n\n## Docs\n\nhttps://jar-docs.vercel.app (built with Jar obviously!)\n\n## Features\n\nJar uses file-system routing.\n\nPages are Python files that render content. They're put in the `pages` directory.\n\n- Build pages aka [Static Files](https://vercel.com/docs/build-output-api/v3#vercel-primitives/static-files)\n- Fresh pages aka [Serverless Functions](https://vercel.com/docs/build-output-api/v3#vercel-primitives/serverless-functions)\n- Regenerated pages aka [Prerender Functions](https://vercel.com/docs/build-output-api/v3#vercel-primitives/prerender-functions)\n\nPublic files (like CSS and other media files) go in the `public` directory and are served from the root path.\n\nCheckout the source for the [kitchen sink example](https://github.com/healeycodes/jar/tree/main/examples/kitchensink), or [the docs website](https://github.com/healeycodes/jar/tree/main/examples/docs).\n\nA typical project is structured like this:\n\n```text\nproject/\n├─ pages/\n│  ├─ index.py\n├─ public/\n│  ├─ favicon.ico\n```\n\n### Build pages\n\nGenerated once at build time. Served as a static file.\n\n```python\nimport time\n\ndef render(data):\n    return f\"\u003ch1\u003e{data['text']} I was built at {data['time']}\u003c/h1\u003e\", {}\n\ndef data():\n    return {\n        \"text\": \"Hello, World!\",\n        \"time\": time.time(),\n    }\n```\n\n### Fresh pages\n\nGenerated for each request. Similar to Server-Side Rendering (SSR).\n\n```python\nimport json\nimport time\n\n\ndef render(data):\n    content = f\"\u003ch1\u003eFresh Page rendered at {data['time']}\u003c/h1\u003e\"\n    content += f\"\u003ccode\u003e{data['request']}\u003c/code\u003e\"\n    return content, {}\n\n\ndef data(request):\n    return {\n        \"time\": time.time(),\n        \"request\": json.dumps({\n            \"method\": request.method,\n            \"path\": request.path,\n            \"headers\": request.headers,\n            \"body\": request.body\n        }, indent=4)\n    }\n\n\ndef config():\n    return {\n        \"fresh\": {}\n    }\n```\n\n### Regenerated Pages\n\nSimilar to Next.js's [Incremental Static Regeneration](https://nextjs.org/docs/basic-features/data-fetching/incremental-static-regeneration).\n\n```python\nimport time\n\n\ndef render(data):\n    return f\"\u003ch1\u003eRegenerated Page, last rendered at {data['time']}\u003c/h1\u003e\", {}\n\ndef data(request=None):\n    return {\n        \"time\": time.time(),\n    }\n\ndef config():\n    return {\n        \"regenerate\": {\n            \"every\": 5\n        }\n    }\n```\n\n## More on the API\n\nThe `data` and `config` functions are optional. The properties that `config` returns defines the type of page. The default page is a build page.\n\nBuild pages don't have access to a request object.\n\nThe response that `render` returns is a tuple of `body, meta` where `meta` can have `status_code: int` and/or `headers: dict` keys e.g. `{\"status_code\": 200, \"headers\": {\"some\":\"header\"}}`.\n\n## More on Packages\n\nIf you are using packages (i.e. something you install with `pip`) you have to install them locally inside your project before building the project with the CLI.\n\ne.g. with `pip` you can run `pip3 install -r requirements.txt --target .` at the project's root.\n\nSee how the docs website is deployed for an example of this ([deploy-docs.sh](https://github.com/healeycodes/jar/blob/main/deploy-docs.sh)).\n\n## Tests\n\n- `pip3 install -r framework/requirements.txt`\n- `pytest`\n\n## Deploy Docs\n\n`./deploy-docs.sh`\n\n## Deploy Kitchen Sink\n\n- `pip3 install -r framework/requirements.txt`\n- `python3 framework/cli.py build examples/kitchensink`\n- `cd build \u0026\u0026 vercel --prebuilt`\n","funding_links":[],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhealeycodes%2Fjar","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhealeycodes%2Fjar","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhealeycodes%2Fjar/lists"}