{"id":15046233,"url":"https://github.com/springtype-org/st-open-api","last_synced_at":"2025-10-26T13:31:03.810Z","repository":{"id":39802152,"uuid":"266250266","full_name":"springtype-org/st-open-api","owner":"springtype-org","description":"Generates API client SDKs from an OpenAPI specification written in OpenAPI version 3.x.x. The SDKs are generated as TypeScript or JavaScript code.","archived":false,"fork":false,"pushed_at":"2024-01-03T16:11:19.000Z","size":815,"stargazers_count":3,"open_issues_count":1,"forks_count":6,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-05T03:02:20.655Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","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/springtype-org.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}},"created_at":"2020-05-23T02:46:20.000Z","updated_at":"2023-08-23T09:37:38.000Z","dependencies_parsed_at":"2023-02-10T11:25:15.492Z","dependency_job_id":"6141eed7-434f-4f5d-88bc-9d9f679f7aa0","html_url":"https://github.com/springtype-org/st-open-api","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/springtype-org%2Fst-open-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/springtype-org%2Fst-open-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/springtype-org%2Fst-open-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/springtype-org%2Fst-open-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/springtype-org","download_url":"https://codeload.github.com/springtype-org/st-open-api/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219862887,"owners_count":16555951,"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":[],"created_at":"2024-09-24T20:52:53.396Z","updated_at":"2025-10-26T13:31:03.453Z","avatar_url":"https://github.com/springtype-org.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# st-open-api\n\n`st-open-api` generates API client SDKs from an OpenAPI specification written in OpenAPI version 3.x.x.\nThe SDKs are generated as TypeScript or JavaScript code.\n\n## Features\n\n- YAML and JSON spec syntax\n- JavaScript and TypeScript code generation\n- Load OpenAPI spec as JSON directly from a remote endpoint (e.g. Swagger endpoint)\n- Browser (`XMLHttpRequest`) and Node.js HTTP client variants\n- React provider code generation\n- Singleton code generation\n- Class name suffixing\n- Quasi-global HTTP request and response interceptor functions (useful for e.g. logging, auth, token refreshing etc.)\n\n## Examples\n\nPlease take a look at the `examples` directory. A simple example call would be:\n\n`npx st-open-api  -s ./examples/petstore-api.yaml -o ./examples/petstore-api-client -t`\n\n## CLI Options\n````\n  -v, --version                  output the current version\n  -s, --source \u003csource\u003e          The path or url to an open-api json file\n  -o, --output \u003coutputPath\u003e      The path where files are generated to\n  -f, --force                    Force generation also if validation fails\n  -i, --interceptor              Force in service class to add an interceptor (default: false)\n  -d, --debug                    Print debug messages\n  -l, --language [language]      choose your language (js, jsOnly, ts) (default: \"ts\")\n  -n, --suffix \u003cServiceSuffix\u003e   the suffix for an generated service class (default: \"Service\")\n  -r, --react                    create react provider component (default: false)\n  -t, --static                   create static services (default: false)\n  -y, --type                     use types instead of enumerations\n  -c, --component                only build components, this flag will disable all others (default: false)\n  -p, --provider                 used to set the provider from \"browser\" to e.g. \"node\" (default: \"browser\")\n  -h, --help                     display help for command\n````\n\n### Local Development\n\nWorking on the codebase of this project requires changing the CLI/generation code and being able to test it.\nTherefore, you can run `yarn watch` to let `tsc`, the TypeScript compiler run continuously, including watching \nfor changes and re-compilation.\n\nTo run the program locally, call: `yarn start --` and add the CLI arguments after that, for example:\n\n`yarn start -- -s ./examples/petstore-api.yaml -o ./examples/petstore-api-client`\n\n### Public API\n\nTo configure and use the generated client, three simple properties can be set:\n\n**requestInterceptor**: is called before any request; here you can manipulate every request parameter, for example add an api-token header\n\n**responseInterceptor**: is called after any request, here you can run code to log requests, or do some token validation check and refresh a JWT token automatically\n \n**endpointUrl**: add here the endpoint url that will be set in every request as a prefix to the endpoint URL defined in the OpenAPI spec\n\n#### TypeScript/Node.js\n\n`example-usage.ts`:\n````ts\n\n// for Node.js usage (provider Node.js)\n\n// import the generated client service class\nimport { V1_SERVICE } from \"./examples/unified-api-client/constant/open-api-services\";\n// import the quasi-global openApi object\nimport { openApi } from \"./examples/unified-api-client/function/open-api\";\n// types are generated, so lets use them\nimport { IOffsetResponse } from \"./examples/unified-api-client/interface/components/i-offset-response\";\n\n// an async IIFE for top-level-await\n(async() =\u003e {\n  // define the actual base endpoint URL to call\n  openApi.endpointUrl = 'https://some.nice.domain'\n\n  // actually use the generated code to call the API\n  const response: Promise\u003cIOffsetResponse\u003e = await V1_SERVICE.createOffset({\n      contactInfo: {\n          city: '...',\n          ...\n      },\n      ...\n  });\n  ...\n\n})()\n\n````\n\n#### TypeScript/React\n\n`ExampleUsage.tsx`:\n\n````tsx\nimport React from \"react\";\n\n// import the quasi-global openApi object\nimport { openApi } from \"./examples/unified-api-client/function/open-api\";\n// import the generated Provider component\nimport { OpenApiProvider } from \"./examples/unified-api-client/provider/open-api-provider\";\n\nexport function OffsetApiClient() {\n\n  // define the actual base endpoint URL to call\n  openApi.endpointUrl = 'https://some.nice.domain'\n\n  // return the provider\n  return \u003cOpenApiProvider\u003e\u003c/OpenApiProvider\u003e\n}\n````\n\n`SomeOtherComponent.tsx`:\n\n````tsx\nimport React, { useContext, useState } from \"react\";\n\n// import the quasi-global openApi object\nimport { openApi } from \"./examples/unified-api-client/function/open-api\";\n// import the generated Provider component\nimport { OpenApiProvider } from \"./examples/unified-api-client/provider/open-api-provider\";\n\nexport function SomeOtherComponent() {\n\n  const offsetApi = useContext(OpenApiProvider)\n  const [offsetResonse, setOffsetResponse] = useState\u003cIOffsetResponse\u003e({})\n \n useEffect(() =\u003e {\n   (async() =\u003e {\n\n  // actually use the generated code to call the API\n    const response: Promise\u003cIOffsetResponse\u003e = await offsetApi.createOffset({\n        contactInfo: {\n            city: '...',\n            ...\n        },\n        ...\n    });\n\n    setOffsetResponse(response)\n\n   })()\n })\n\n return \u003cdiv\u003eOffset response: {JSON.stringify(offsetResonse, null, 2)}\u003c/div\u003e\n}\n````\n\n#### Request Interceptor\n\nYou can customize request data using the `async requestInterceptor(request: IRequest)` callback function:\n\n````ts\n// this can be useful for Authorization using JWT tokens or other use-cases\n// requestInterceptor is called before the actual HTTP request is sent to the server\nopenApi.requestInterceptor = async(request: IRequest) =\u003e {\n\n    console.log('requestInterceptor called with request', request)\n\n    // e.g. set a token to be used by all requests\n    request.header['Authorization'] = `Bearer ${SOME_JWT_TOKEN}`\n\n    // e.g. add some custom headers to any request or filter using logic based on request object\n    request.header['X-Forwarded-For'] = '...'\n\n    return request\n}\n````\n\n#### Response Interceptor\n\nWhen a response is returned, you might want to do addtional tasks; in debug mode\nit might be helpful to log in general; in error cases, it might be helpful to\nput a general purpose retry logic -- sometimes you might want to refresh the\nJWT token automatically (exchange long term token with a short-term token): \n\n\n````ts\nlet retryCount = 0;\n\n// responseInterceptor is called before the response is resolve()'d\n// is is called for non-error and error cases (that's why error is optional)\nopenApi.responseInterceptor = async(\n  request: IRequest, response: Response, retry: HttpRequestFn, error?: IError\n) =\u003e {\n\n    // the retry() function is a reference to the function that has been called\n    // internally to run the request. The request object contains all parameters\n    // so we can mutate them if necessary, and rety.\n\n    console.log('responseInterceptor called with', request, response, retry, error)\n\n    retryCount++;\n    \n    request.header['X-Retry-Count'] = retryCount\n\n    if (error \u0026\u0026 retryCount \u003c= 3) {\n        await retry(request)\n    }\n\n    // this method is async and awaited in outer scope.\n    // you can run more requests here just by using the retry() function reference\n    // as long as it is awaited\n}\n````\n\n#### Error handler\n\nThe error handler is meant to be implemented for general error handling.\nIt is called if the HTTP status is not between 200 and 399 or in any case\nof a JavaScript runtime error while executing the HTTP request.\n\nIf the error handler is implemented, it must return the error object\nprovided, else the internal implementation will mask and ignore the error.\n\n````ts\n// errorHandler is called before the responseInterceptor is invoked\n// is can be used to filter and mask errors by returning false\nopenApi.errorHandler = (error: IError) =\u003e {\n\n    console.log('errorHandler called with error', error)\n\n    // e.g. do tracing here\n\n    return error;\n}\n````\n\n## Roadmap\n- add suffix for enumerations and add a get values list \n- naming strategy hook function (service naming from path)\n- generate end-2-end integration tests for each client (usage examples)\n- support for a config file to set all the options\n- add support to different HTTP client libraries\n- runtime typechecks for request and reponse\n- add support other target languages\n  - Java\n  - PHP\n  - Go\n  - .NET","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspringtype-org%2Fst-open-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspringtype-org%2Fst-open-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspringtype-org%2Fst-open-api/lists"}