{"id":13805582,"url":"https://github.com/hxjo/fastapi-inertia","last_synced_at":"2025-05-13T19:31:27.550Z","repository":{"id":231340697,"uuid":"781530912","full_name":"hxjo/fastapi-inertia","owner":"hxjo","description":"An Inertia.js adapter for FastAPI, using the dependency injection system","archived":false,"fork":false,"pushed_at":"2024-05-08T15:12:17.000Z","size":221,"stargazers_count":9,"open_issues_count":1,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-05-18T16:47:21.731Z","etag":null,"topics":["fastapi","inertia","inertiajs","python"],"latest_commit_sha":null,"homepage":"https://pypi.org/project/fastapi-inertia/","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/hxjo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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-04-03T14:59:38.000Z","updated_at":"2024-05-31T13:29:34.040Z","dependencies_parsed_at":null,"dependency_job_id":"2a6874f7-617b-45c4-85d7-0670dc11f611","html_url":"https://github.com/hxjo/fastapi-inertia","commit_stats":null,"previous_names":["hxjo/fastapi-inertia-vue","hxjo/fastapi-inertia"],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hxjo%2Ffastapi-inertia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hxjo%2Ffastapi-inertia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hxjo%2Ffastapi-inertia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hxjo%2Ffastapi-inertia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hxjo","download_url":"https://codeload.github.com/hxjo/fastapi-inertia/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225254351,"owners_count":17445166,"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":["fastapi","inertia","inertiajs","python"],"created_at":"2024-08-04T01:01:02.644Z","updated_at":"2025-05-13T19:31:27.530Z","avatar_url":"https://github.com/hxjo.png","language":"Python","funding_links":[],"categories":["Adapters"],"sub_categories":["Server-side"],"readme":"# Inertia.js FastAPI Adapter\n\n\u003c!-- TOC --\u003e\n\n- [Inertia.js FastAPI Adapter](#inertiajs-fastapi-adapter)\n  - [Contribution](#contribution)\n  - [Installation](#installation)\n  - [Configuration](#configuration)\n  - [Examples](#examples)\n  - [Usage](#usage)\n    - [Create a Jinja2Template](#create-a-jinja2template)\n    - [Set up the dependency](#set-up-the-dependency)\n    - [Rendering a page](#rendering-a-page)\n    - [Rendering assets](#rendering-assets)\n    - [Sharing data](#sharing-data)\n    - [Flash messages](#flash-messages)\n    - [Flash errors](#flash-errors)\n    - [Redirect to an external URL](#redirect-to-an-external-url)\n    - [Redirect back](#redirect-back)\n    - [Enable SSR](#enable-ssr)\n  - [Frontend documentation](#frontend-documentation)\n    - [For a classic build](#for-a-classic-build)\n    - [For a SSR build](#for-a-ssr-build)\n    - [Performance note](#performance-note)\n\n## Contribution\n\nIf you wish to contribute, please follow the [contribution guide](CONTRIBUTION.md)\n\n## Installation\n\nYou can install the package via pip:\n\n```bash\npip install fastapi-inertia\n```\n\n## Configuration\n\nYou can configure the adapter by passing a `InertiaConfig` object to the `Inertia` class.\nThe following options are available:\n\n| key                    | default                | options                                 | description                                                                                                                                  |\n| ---------------------- | ---------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |\n| environment            | development            | development,production                  | The environment to use                                                                                                                       |\n| version                | 1.0.0                  | Any valid string                        | The version of your server                                                                                                                   |\n| json_encoder           | InertiaJsonEncoder     | Any class that extends json.JSONEncoder | The JSON encoder used to encode page data when HTML is returned                                                                              |\n| manifest_json_path     | \"\"                     | Any valid path                          | The path to the manifest.json file. Needed in production                                                                                     |\n| dev_url                | http://localhost:5173  | Any valid url                           | The URL to the development server                                                                                                            |\n| ssr_url                | http://localhost:13714 | Any valid url                           | The URL to the SSR server                                                                                                                    |\n| ssr_enabled            | False                  | True,False                              | Whether to [enable SSR](#enable-ssr). You need to install the `httpx` package, to have set the manifest_json_path and started the SSR server |\n| root_directory         | src                    | Any valid path                          | The directory in which is located the javascript code in your frontend. Will be used to find the relevant files in your manifest.json.       |\n| entrypoint_filename    | main.js                | Any valid file                          | The entrypoint for you frontend. Will be used to find the relevant files in your manifest.json.                                              |\n| assets_prefix          | \"\"                     | Any valid string                        | An optional prefix for your assets. Will prefix the links generated from the assets mentioned in manifest.json.                              |\n| use_flash_messages     | False                  | True,False                              | Whether to use [flash messages](#flash-messages). You need to use Starlette's SessionMiddleware to use this feature                          |\n| flash_message_key      | messages               | Any valid string                        | The key to use for [flash errors](#flash-errors)                                                                                             |\n| use_flash_errors       | False                  | True,False                              | Whether to use flash errors                                                                                                                  |\n| flash_error_key        | errors                 | Any valid string                        | The key to use for flash errors                                                                                                              |\n| templates              | None                   | A Jinja2Templates instance              | The templates instance in which Inertia will look for the `root_template_filename` template                                                  |\n| root_template_filename | index.html             | Any valid jinja2 template file          | The file which will be used to render your inertia application                                                                               |\n| extra_template_context | dict()                 | Any valid dictionary of type Dict[str, Any]                          | Extra context to pass to the template. You can use it to pass any variable to the template |\n\n## Examples\n\nYou can see different full examples in the `examples` directory\n\n## Usage\n\n### Create a Jinja2Template\n\nIn order to use the Inertia.js adapter, you have to create a Jinja2Template that the library will use.\n\nIt **must** have both an `inertia_head` and an `inertia_body` tag in it.\n\n- `inertia_head` is where the library will place the code that supposedly goes inside the HTML `head` tag\n- `inertia_body` is where the library will place the code that supposedly goes inside the HTML `body` tag\n\nYou can find the simplest example in `inertia/tests/templates/index.html`.  \nYou should then register the folder in which you put this file as the directory of your Jinja2Templates\n\n```python\ntemplates = Jinja2Templates(directory=template_dir)\n```\n\nThis option should be passed to the InertiaConfig class presented below, under the `templates` key.\nIf you choose a different template file name than `index.html`, you can also pass the `root_template_filename` key with, as value, your template file name.\n\n### Set up the dependency\n\nThis Inertia.js adapter has been developed to be used as a FastAPI dependency.\nTo use it, you first need to set up the dependency, with your desired configuration.\n\n`inertia_dependency.py`\n\n```python\nfrom fastapi import Depends\nfrom typing import Annotated\nfrom inertia import InertiaConfig, inertia_dependency_factory, Inertia\n\ninertia_config = InertiaConfig(\n        # Your desired configuration\n    )\n\ninertia_dependency = inertia_dependency_factory(\n    inertia_config\n)\n\nInertiaDependency = Annotated[Inertia, Depends(inertia_dependency)]\n```\n\nYou can then access the `InertiaDependency` in your route functions, and use it to render your pages.\n\n### Rendering a page\n\nTo render a page, you can use the `render` method of the `Inertia` class. It takes two arguments:\n\n- The name of the page\n- The data to pass to the page\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\n\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\n\n@app.get('/', response_model=None)\nasync def index(inertia: InertiaDependency) -\u003e InertiaResponse:\n     return inertia.render('Index', {\n          'name': 'John Doe'\n     })\n```\n\n### Rendering assets\n\nAs your front-end framework likely references assets that are not served by FastAPI,\nyou need to mount a static directory to serve these assets.\n\n`main.py`\n\n```python\nimport os\nfrom fastapi import FastAPI\nfrom fastapi.staticfiles import StaticFiles\nfrom inertia_dependency import inertia_config\n\n\napp = FastAPI()\nwebapp_dir = (\n    os.path.join(os.path.dirname(__file__), \"..\", \"webapp\", \"dist\")\n    if inertia_config.environment != \"development\"\n    else os.path.join(os.path.dirname(__file__), \"..\", \"webapp\", \"src\")\n)\n\napp.mount(\"/src\", StaticFiles(directory=webapp_dir), name=\"src\")\napp.mount(\n    \"/assets\", StaticFiles(directory=os.path.join(webapp_dir, \"assets\")), name=\"assets\"\n)\n```\n\n### Sharing data\n\nTo share data, in Inertia, is basically to add data before even entering your route.\nThis is useful, for example, to add a user to all your pages that expects your user to be logged in.\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\n\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\n\ndef current_user(inertia: InertiaDependency):\n    inertia.share(user={\n        'name': 'John Doe'\n    })\n\n@app.get('/', response_model=None, dependencies=[Depends(current_user)])\nasync def index(inertia: InertiaDependency) -\u003e InertiaResponse:\n    \"\"\"\n    Because of the dependency, and as we are sharing the user data, the user data will be available in the page.\n    \"\"\"\n    return inertia.render('Index')\n```\n\n### Flash messages\n\nWith the inertia dependency, you have access to a `flash` helper method that allows you to add flash messages to your pages.\nThis is useful to display messages to the user after a form submission, for example.\nThose messages are called `flash` messages as they are only displayed once.  \nYou need to have set `use_flash_messages` to `True` in your configuration to use this feature.\nYou need to have the `SessionMiddleware` enabled in your application to use this feature.\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom starlette.middleware.sessions import SessionMiddleware\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\n\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\napp.add_middleware(SessionMiddleware, secret_key=\"secret\")\n\n\n@app.get('/', response_model=None)\nasync def index(inertia: InertiaDependency) -\u003e InertiaResponse:\n    inertia.flash('Index was reached successfully', category='success')\n    return inertia.render('Index')\n```\n\n### Flash errors\n\nIf you handle form submissions in your application, and if you do all validation at the pydantic level,\na malformed payload will raise a `RequestValidationError` exception.\nYou can use the `inertia_request_validation_exception_handler` to handle this exception and display the errors to the user.\nIt supports error bags, so you can display multiple errors at once.\nIf the request is not from Inertia, it will fallback to FastAPI's default error handling.  \nIn order to use this feature, you need to have set `use_flash_errors` to `True` in your configuration.\nYou also need to have the `SessionMiddleware` enabled in your application to use this feature.\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom pydantic import BaseModel, model_validator\nfrom typing import Any\nfrom fastapi.exceptions import RequestValidationError\nfrom starlette.middleware.sessions import SessionMiddleware\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler, inertia_request_validation_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\n\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\napp.add_exception_handler(RequestValidationError, inertia_request_validation_exception_handler)\napp.add_middleware(SessionMiddleware, secret_key=\"secret\")\n\n\nclass Form(BaseModel):\n    name: str\n\n    @model_validator(mode=\"before\")\n    @classmethod\n    def name_must_contain_doe(cls, data: Any):\n        if 'Doe' not in data.name:\n            raise ValueError('Name must contain Doe')\n\n@app.post('/', response_model=None)\nasync def index(data: Form, inertia: InertiaDependency) -\u003e InertiaResponse:\n    return inertia.render('Index')\n```\n\n### Redirect to an external URL\n\nIf you want to redirect the user to an external URL, you can use the `location` method of the `Inertia` class.\nIt takes one argument: the URL to redirect to.\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\n\n@app.get('/', response_model=None)\nasync def index(inertia: InertiaDependency) -\u003e InertiaResponse:\n    return inertia.location('https://google.fr')\n```\n\n### Redirect back\n\nIf you want to redirect the user back (for example, after a form submission), you can use the `back` method of the `Inertia` class.\nIt will use the `Referer` header to redirect the user back.\nIf you're on a `GET` request, the status code will be `307`. Otherwise, it will be `303`.\nThat ways, it will trigger a new GET request to the referer URL.\n\n`main.py`\n\n```python\nfrom fastapi import FastAPI, Depends\nfrom inertia import InertiaResponse, InertiaVersionConflictException, inertia_version_conflict_exception_handler\nfrom inertia_dependency import InertiaDependency\n\napp = FastAPI()\napp.add_exception_handler(InertiaVersionConflictException, inertia_version_conflict_exception_handler)\n\n@app.get('/', response_model=None)\nasync def index(inertia: InertiaDependency) -\u003e InertiaResponse:\n    return inertia.back()\n```\n\n### Enable SSR\n\nTo enable SSR, you need to set `ssr_enabled` to `True` in your configuration.\nYou also need to have set the `manifest_json_path` to the path of your `manifest.json` file.\nYou need to have the `httpx` package installed to use this feature.\nThis can be done through the following command:\n\n```bash\npip install httpx\n```\n\n## Frontend documentation\n\nThere is no particular caveats to keep in mind when using this adapter.\nHowever, here's an example of how you would set up your frontend to work with this adapter.\n\n### For a classic build\n\n\u003e [!NOTE]  \n\u003e To build the project, you can run the `vite build` command\n\n`vite.config.js`\n\n```javascript\nimport { fileURLToPath } from \"node:url\";\nimport { dirname } from \"path\";\n\nimport { defineConfig } from \"vite\";\nimport vue from \"@vitejs/plugin-vue\";\n\nconst projectRoot = dirname(fileURLToPath(import.meta.url));\n// https://vitejs.dev/config/\nexport default defineConfig({\n  plugins: [vue()],\n  resolve: {\n    alias: {\n      \"@\": `${projectRoot}/src`,\n    },\n  },\n  build: {\n    manifest: \"manifest.json\",\n    outDir: \"dist\",\n    rollupOptions: {\n      input: \"src/main.js\",\n    },\n  },\n});\n```\n\n`main.js`\n\n```javascript\nimport { createApp, h } from \"vue\";\nimport { createInertiaApp } from \"@inertiajs/vue3\";\n\ncreateInertiaApp({\n  resolve: (name) =\u003e {\n    const pages = import.meta.glob(\"./Pages/**/*.vue\", { eager: true });\n    return pages[`./Pages/${name}.vue`];\n  },\n  setup({ el, App, props, plugin }) {\n    createApp({ render: () =\u003e h(App, props) })\n      .use(plugin)\n      .mount(el);\n  },\n});\n```\n\n### For a SSR build\n\n\u003e [!NOTE]  \n\u003e To build the project, you can run the `vite build` and `vite build --ssr` commands  \n\u003e To serve the Inertia SSR server, you can run the `node dist/ssr/ssr.js` command\n\n`vite.config.js`\n\n```javascript\nimport { fileURLToPath } from \"node:url\";\nimport { dirname } from \"path\";\n\nimport { defineConfig } from \"vite\";\nimport vue from \"@vitejs/plugin-vue\";\n\nconst projectRoot = dirname(fileURLToPath(import.meta.url));\n// https://vitejs.dev/config/\nexport default defineConfig(({ isSsrBuild }) =\u003e ({\n  plugins: [vue()],\n  resolve: {\n    alias: {\n      \"@\": `${projectRoot}/src`,\n    },\n  },\n  build: {\n    manifest: isSsrBuild ? false : \"manifest.json\",\n    outDir: isSsrBuild ? \"dist/ssr\" : \"dist/client\",\n    rollupOptions: {\n      input: isSsrBuild ? \"src/ssr.js\" : \"src/main.js\",\n    },\n  },\n}));\n```\n\n`main.js`\n\n```javascript\nimport { createSSRApp, h } from \"vue\";\nimport { createInertiaApp } from \"@inertiajs/vue3\";\n\ncreateInertiaApp({\n  resolve: (name) =\u003e {\n    const pages = import.meta.glob(\"./Pages/**/*.vue\", { eager: true });\n    return pages[`./Pages/${name}.vue`];\n  },\n  setup({ el, App, props, plugin }) {\n    createSSRApp({ render: () =\u003e h(App, props) })\n      .use(plugin)\n      .mount(el);\n  },\n});\n```\n\n`ssr.js`\n\n```javascript\nimport { createInertiaApp } from \"@inertiajs/vue3\";\nimport createServer from \"@inertiajs/vue3/server\";\nimport { renderToString } from \"@vue/server-renderer\";\nimport { createSSRApp, h } from \"vue\";\n\ncreateServer((page) =\u003e\n  createInertiaApp({\n    page,\n    render: renderToString,\n    resolve: (name) =\u003e {\n      const pages = import.meta.glob(\"./Pages/**/*.vue\", { eager: true });\n      return pages[`./Pages/${name}.vue`];\n    },\n    setup({ App, props, plugin }) {\n      return createSSRApp({\n        render: () =\u003e h(App, props),\n      }).use(plugin);\n    },\n  })\n);\n```\n\n### Performance note\n\nWith the implementation proposed above, you'll be loading the whole page on the first load.\nThis is because everything will be bundled in the same file.\nIf you want to split your code, you can use the following implementation.\n\n`helper.js` (taken from [laravel vite plugin inertia helpers](https://github.com/laravel/vite-plugin/blob/1.x/src/inertia-helpers/index.ts))\n\n```javascript\nexport async function resolvePageComponent\u003cT\u003e(\n  path: string | string[],\n  pages: Record\u003cstring, Promise\u003cT\u003e | (() =\u003e Promise\u003cT\u003e)\u003e\n): Promise\u003cT\u003e {\n  for (const p of Array.isArray(path) ? path : [path]) {\n    const page = pages[p];\n\n    if (typeof page === \"undefined\") {\n      continue;\n    }\n\n    return typeof page === \"function\" ? page() : page;\n  }\n\n  throw new Error(`Page not found: ${path}`);\n}\n```\n\n`main.js`\n\n```javascript\nimport { createApp, h } from \"vue\";\nimport { createInertiaApp } from \"@inertiajs/vue3\";\nimport { resolvePageComponent } from \"@/helper.js\";\n\ncreateInertiaApp({\n  resolve: (name) =\u003e {\n    return resolvePageComponent(\n      `./Pages/${name}.vue`,\n      import.meta.glob(\"./Pages/**/*.vue\")\n    );\n  },\n  setup({ el, App, props, plugin }) {\n    createApp({ render: () =\u003e h(App, props) })\n      .use(plugin)\n      .mount(el);\n  },\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhxjo%2Ffastapi-inertia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhxjo%2Ffastapi-inertia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhxjo%2Ffastapi-inertia/lists"}