{"id":15288711,"url":"https://github.com/manawasp/integrate-openapi-to-ts-app","last_synced_at":"2026-01-05T22:06:14.294Z","repository":{"id":50404559,"uuid":"518976232","full_name":"manawasp/integrate-openapi-to-ts-app","owner":"manawasp","description":"Example to limit api integration friction in a typescript application","archived":false,"fork":false,"pushed_at":"2022-08-25T20:22:02.000Z","size":234,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-11T14:46:08.664Z","etag":null,"topics":["api","fastapi","openapi","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/manawasp.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}},"created_at":"2022-07-28T19:49:30.000Z","updated_at":"2022-08-22T15:08:51.000Z","dependencies_parsed_at":"2022-08-29T11:21:57.143Z","dependency_job_id":null,"html_url":"https://github.com/manawasp/integrate-openapi-to-ts-app","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manawasp%2Fintegrate-openapi-to-ts-app","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manawasp%2Fintegrate-openapi-to-ts-app/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manawasp%2Fintegrate-openapi-to-ts-app/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manawasp%2Fintegrate-openapi-to-ts-app/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manawasp","download_url":"https://codeload.github.com/manawasp/integrate-openapi-to-ts-app/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244931585,"owners_count":20534009,"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":["api","fastapi","openapi","typescript"],"created_at":"2024-09-30T15:52:26.970Z","updated_at":"2026-01-05T22:06:14.267Z","avatar_url":"https://github.com/manawasp.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Integrate OpenAPI to TS app\n\nDemonstrate a strategy to limit api integration friction in a typescript application based on the openapi generation.\n\n\u003e Application could be split into two parts: frontend and backend. Extra attention will be required as we need to integrate the api communication.\n\u003e We will explore a solution to avoid mistake and facilitate integration.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./images/overview.png\"\u003e\n\u003c/p\u003e\n\n## Summary\n\n- [Integrate OpenAPI to TS app](#integrate-openapi-to-ts-app)\n  - [Summary](#summary)\n  - [Tools](#tools)\n  - [Exploration](#exploration)\n    - [1. Generate the OpenAPI from the API code source](#1-generate-the-openapi-from-the-api-code-source)\n      - [Python](#python)\n    - [2. Generate \u0026 use the typescript client](#2-generate--use-the-typescript-client)\n    - [3. Models](#3-models)\n  - [Automating](#automating)\n    - [1. Generate NPM typescript client](#1-generate-npm-typescript-client)\n      - [Github Actions](#github-actions)\n      - [Gitlab CI](#gitlab-ci)\n    - [2. Integration](#2-integration)\n  - [Playground](#playground)\n  - [Contributing](#contributing)\n  - [License](#license)\n\n## Tools\n\nThis repository uses:\n\n- [OpenAPI TypeScript codegen](https://github.com/ferdikoomen/openapi-typescript-codegen#openapi-typescript-codegen): generates typescript clients based on the openapi specification\n- [Github Action](https://docs.github.com/en/actions): Continuous Integration Job, to generate and publish the generated typescript client to NPM\n- [FastAPI](https://fastapi.tiangolo.com/): Python framework to build api and to generate openapi\n- [Vitesse lite](https://github.com/antfu/vitesse-lite): Vue boilerplate using typescript\n- [Docker compose](https://docs.docker.com/compose/): To quickly run the application\n\n## Exploration\n\nQuick overview of how to generate step by step a typescript client from a FastAPI\n\n### 1. Generate the OpenAPI from the API code source\n\n#### Python\n\nBuild a [FastAPI](https://fastapi.tiangolo.com/) which natively generates openapi.\n\n**[api/routers/recipes_comments.py](./api/routers/recipes_comments.py)**\n\n```python\nrouter = APIRouter(\n    tags=[\"recipesComments\"],\n    responses={\"403\": ERROR_RESPONSES[403]},\n)\n\n@router.post(\n    \"/recipes/{recipe_id}/comments\",\n    name=\"recipes comments create\",\n    ...\n)\ndef recipes_comments_create():\n    ...\n```\n\nThe following script generates the `openapi.json`,\n\n**[api/openapi.py](./api/openapi.py)**\n\n```python\nimport json\n\nfrom fastapi import FastAPI\nfrom fastapi.routing import APIRoute\nfrom fastapi.openapi.utils import get_openapi\n\nfrom main import app\n\n\ndef use_route_names_as_operation_ids(app: FastAPI) -\u003e None:\n    for route in app.routes:\n        if isinstance(route, APIRoute):\n            route.operation_id = route.name.replace(\" \", \"_\")\n\n\nuse_route_names_as_operation_ids(app)\n\nprint(\"Creating openapi.json file...\")\nwith open(\"openapi.json\", \"w\") as openapi_file:\n    openapi_schema = get_openapi(\n        title=\"My App\",\n        version=\"0.0.1\",\n        description=\"This is a very random API\",\n        routes=app.routes,\n    )\n    json.dump(openapi_schema, openapi_file)\nprint(\"openapi.json file generated\")\n```\n\n_Note: As FastAPI generates too complex `OperationId` the script overrides it. [More detail from the FastAPI doc](https://fastapi.tiangolo.com/advanced/path-operation-advanced-configuration/#exclude-from-openapi)._\n\n```sh\n[api] (venv) $ python openapi.py`\nCreating openapi.json file...\nopenapi.json file generated\n```\n\n### 2. Generate \u0026 use the typescript client\n\n```sh\n\u003e npx openapi-typescript-codegen --input openapi.json --output clients --useOptions --name FoodyClient\n```\n\nIntegrate the generated client to the typescript app\n\n```ts\nimport { FoodyClient } from 'clients'\n\nconst app = new FoodyClient({})\nconst client = app.RecipesCommentsService\nclient.recipesCommentsCreate({ ... })\n```\n\n### 3. Models\n\nResponses and requests class are also converted to typescript interface and can be found in the [models/](./example/clients/models/) directory.\n\n**[api/routers/schemas/recipes_comments.py](./api/routers/schemas/recipes_comments.py)**\n\n```python\nclass RecipeComment(BaseModel):\n    id: int\n    message: str\n```\n\n**[examples/clients/models/RecipesComments.ts](./examples/clients/models/RecipesComments.ts)**\n\n```ts\nexport type RecipeComment = {\n    id: number;\n    message: string;\n};\n```\n\n## Automating\n\n### 1. Generate NPM typescript client\n\nEverytime a new tag is added to the api, the following github workflow will publish the package (Can be triggered instead when a release is created).\n\n#### Github Actions\n\n**[.github/workflows/publish.yml](./.github/workflow/publish.yml)**\n\n```yml\nname: Publish to NPM registry\non:\n  push:\n    tags:\n      - '*'\n  # release:\n  #   types: [created]\n\ndefaults:\n run:\n  working-directory: ./api\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout\n        uses: actions/checkout@v2\n      - name: Setup Python\n        uses: actions/setup-python@v4\n        with:\n          python-version: '3.10'\n      - name: Install dependencies\n        run: pip install -r requirements.txt\n      - name: Generate openapi\n        run: python openapi.py\n      - name: Setup Node\n        uses: actions/setup-node@v2\n        with:\n          node-version: '18.x'\n          registry-url: 'https://registry.npmjs.org'\n      - name: Convert OpenAPI to TS Client\n        run: npx --yes openapi-typescript-codegen --input openapi.json --output clients --useOptions --name FoodyClient\n      - name: Set npm version\n        run:  npm version ${CI_COMMIT_TAG} --no-git-tag-version\n      - name: Publish package on NPM\n        run: npm publish\n        env:\n          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}\n```\n\n#### Gitlab CI\n\n```yml\nimage: python:3.10.6-slim\n\ncache:\n  key:\n    files:\n      - api/requirements.txt\n      - api/requirements-test.txt\n  paths:\n    - .cache/pip\n    - venv/\n\ngenerate_openapi:\n  stage: deploy\n  before_script:\n    - python -V # Print out python version for debugging\n    - pip install virtualenv\n    - virtualenv venv\n    - source venv/bin/activate\n    - pip install -r api/requirements.txt -r api/requirements-test.txt\n  script:\n    - cd api/\n    - python openapi.py\n  artifacts:\n    paths:\n      - api/openapi.json\n  only:\n    - tags\n\npublish_package:\n  image: node:18.7.0-alpine\n  stage: .post\n  script:\n    - cd api/\n    - npx --yes openapi-typescript-codegen --input openapi.json --output clients --useOptions --name FoodyClient\n    - npm version ${CI_COMMIT_TAG} --no-git-tag-version\n    - NPM_PACKAGE_NAME=$(node -p \"require('./package.json').name\")\n    - NPM_PACKAGE_VERSION=$(node -p \"require('./package.json').version\")\n    - |\n      {\n        npm publish \u0026\u0026\n        echo \"Successfully published version ${NPM_PACKAGE_VERSION} of ${NPM_PACKAGE_NAME} to NPM registry\"\n      } || {\n        echo \"No new version of ${NPM_PACKAGE_NAME} published. This is most likely because version ${NPM_PACKAGE_VERSION} already exists in NPM registry.\"; exit 1\n      }\n  only:\n    - tags\n```\n\n### 2. Integration\n\n```sh\npnpm i -S integrate-openapi-to-ts-app\n```\n\n## Playground\n\n```sh\n$ docker compose up\n[+] Running 2/2\n ⠿ Container integrate-openapi-to-ts-app-api-1 Recreated 0.1s\n ⠿ Container integrate-openapi-to-ts-app-app-1 Recreated 0.1s\n...\n```\n\nApplication will be available on [http://127.0.0.1:8080](http://127.0.0.1:8080)\n\n## Contributing\n\nContributions are welcome, don't hesitate to [open discussion](https://github.com/manawasp/integrate-openapi-to-ts-app/discussions).\n\n## License\n\nThe code source is licensed with MIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanawasp%2Fintegrate-openapi-to-ts-app","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanawasp%2Fintegrate-openapi-to-ts-app","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanawasp%2Fintegrate-openapi-to-ts-app/lists"}