DEV Community

Cover image for Generate TypeScript types from Swagger (OpenAPI 3)
Pavel Keyzik
Pavel Keyzik

Posted on • Updated on

Generate TypeScript types from Swagger (OpenAPI 3)

Hi! I'd like to share some code that helped me a lot to work with an API that had been changed often.

Idea

The idea is to generate TypeScript types from Swagger's definition. I found an awesome npm library called @codegena/oapi3ts-cli. To use this you need to store JSON file with API schema locally.

Let's move to code...

Install dependencies

I used axios to fetch data. You can use anything you want.

npm i -D @codegena/oapi3ts-cli axios
Enter fullscreen mode Exit fullscreen mode

Create folders and files that we need

Now let's create the scripts/ folder in the root of your project and add two files (fetch-schema.js and schema-codegen.js) inside of the created folder. Also, we need to create src/typings/ folder where we're gonna save our types and API schema.

// scripts/schema-codegen.js

const cliLib = require('@codegena/oapi3ts-cli');
const cliApp = new cliLib.CliApplication();

cliApp.cliConfig.typingsDirectory = '';
cliApp.createTypings();
Enter fullscreen mode Exit fullscreen mode
// scripts/fetch-schema.js

const axios = require('axios');
const https = require('https');
const fs = require('fs');
const path = require('path');

const instance = axios.create({
  httpsAgent: new https.Agent({
    rejectUnauthorized: false,
  }),
});


/* The code below will create operation names.
Instead of `/api/User/GetList` you'll get `UserGetList` type
that you can use anywhere */

function addOperationIdsToSchema(schema) {
  const data = schema;

  Object.keys(data.paths).forEach((endpointPath) => {
    const operations = Object.keys(data.paths[endpointPath]);

    operations.forEach((operation) => {
      const oprationName = endpointPath.replace('/api/', '').replace(/\//g, '');
      data.paths[endpointPath][operation].operationId = oprationName;
    });
  });

  return data;
}

instance
  .get('https://YOUR_ENDPOINT_TO_SWAGGER/swagger.json')
  .then((response) => {
    const updatedSchema = addOperationIdsToSchema(response.data);
    fs.writeFileSync(
      path.resolve(__dirname, '../src/typings/api-schema.json'),
      JSON.stringify(updatedSchema, null, 2),
    );

    console.log('==> Schema fetched successfully...');
  })
  .catch(console.error);
Enter fullscreen mode Exit fullscreen mode

Update package.json

And one of the last things you need to do is add to package.json these lines:

{
    ...
    "scripts": {
        ...
        "schema:fetch": "node ./scripts/fetch-schema.js",
        "schema:generate": "node ./scripts/schema-codegen.js --srcPath ./src/typings/api-schema.json --destPath ./src/typings/api --separatedFiles false",
        "schema:codegen": "npm run schema:fetch && npm run schema:generate:api"
    }
}
Enter fullscreen mode Exit fullscreen mode

Now you can generate your API schema with this command:

npm run schema:codegen
Enter fullscreen mode Exit fullscreen mode

This command generated src/typings/api/ folder with TypeScript definitions.

If you got into some problems, please, let me know to be able to update the article for future readers.

Discussion (4)

Collapse
hilleer profile image
Daniel Hillmann • Edited

this is a bit weird. You explicitly include cli in the name but I only see examples of using it programmatically? Did I misunderstand or overlook something? :-)

Otherwise seem cool.

en.wikipedia.org/wiki/Command-line...

Collapse
pavelkeyzik profile image
Pavel Keyzik Author

I agree that it seems to be weird but I haven't found anything else in docs of that package.

Collapse
thomasganter profile image
Thomas Ganter

Nice, and I’ll give it a try, but … you might want to correct the first line of those example files, for they are not json but js …

Collapse
pavelkeyzik profile image
Pavel Keyzik Author

Oh, yeah! I'll fix that. Thank you so much