{"_id":"@ab-tag/n8n-openapi-node","name":"@ab-tag/n8n-openapi-node","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@ab-tag/n8n-openapi-node","version":"1.0.0","description":"Turn OpenAPI specs into n8n node","main":"dist/index.js","module":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest"},"repository":{"type":"git","url":"git+https://github.com/ab-tag/n8n-openapi-node.git"},"keywords":["n8n","openapi"],"author":{"name":"ab-tag"},"license":"MIT","bugs":{"url":"https://github.com/ab-tag/n8n-openapi-node/issues"},"bin":{"n8n-openapi-node":"dist/cli/index.js"},"exports":{".":{"import":"./dist/index.js","require":"./dist/index.js"}},"homepage":"https://github.com/ab-tag/n8n-openapi-node#readme","publishConfig":{"access":"public"},"devDependencies":{"@types/jest":"^29.5.13","@types/lodash":"^4.17.7","jest":"^29.7.0","n8n-core":"*","n8n-workflow":"*","ts-jest":"^29.2.5","typescript":"^5.6.2"},"dependencies":{"@clack/prompts":"^0.11.0","javascript-stringify":"^2.1.0","lodash":"^4.17.21","openapi-types":"^12.1.3","pino":"^9.4.0","pino-pretty":"^11.2.2","prettier":"^3.7.4"},"gitHead":"100dfeb61d56a7a3721bd414dfd262fc97a2af59","_id":"@ab-tag/n8n-openapi-node@1.0.0","_nodeVersion":"24.11.1","_npmVersion":"11.6.2","dist":{"integrity":"sha512-MEt6epamaNN8MYuaqazhCWdjKRw/T7CxNKZP3Vlf+2epTfri9hrV3oVCdeh+DA8KfCWn1ayMZTvgIlRoZO7nfQ==","shasum":"b6cfc7d5162f0f1afb6bfb4cf5bcc819b404ef38","tarball":"https://registry.npmjs.org/@ab-tag/n8n-openapi-node/-/n8n-openapi-node-1.0.0.tgz","fileCount":48,"unpackedSize":159876,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDrJxbGf/I5yv7f+YaPB3S7we5SaS0naMklEUqh7aXbhwIgFKt0bL9CNmEDaqNtir4tu44VSMtDMZiLlZOohnCNcIg="}]},"_npmUser":{"name":"allburov","email":"allburov@gmail.com"},"directories":{},"maintainers":[{"name":"allburov","email":"allburov@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/n8n-openapi-node_1.0.0_1765870178616_0.9404969747506073"},"_hasShrinkwrap":false}},"time":{"created":"2025-12-16T07:29:38.555Z","1.0.0":"2025-12-16T07:29:38.754Z","modified":"2025-12-16T07:29:39.040Z"},"maintainers":[{"name":"allburov","email":"allburov@gmail.com"}],"description":"Turn OpenAPI specs into n8n node","homepage":"https://github.com/ab-tag/n8n-openapi-node#readme","keywords":["n8n","openapi"],"repository":{"type":"git","url":"git+https://github.com/ab-tag/n8n-openapi-node.git"},"author":{"name":"ab-tag"},"bugs":{"url":"https://github.com/ab-tag/n8n-openapi-node/issues"},"license":"MIT","readme":"# @ab-tag/n8n-openapi-node\n\n\n![openapi logo](openapi.png)\n![n8n logo](n8n.png)\n\nTurn Your **OpenAPI** (**Swagger**) spec into a **n8n node**!\n\n[![npm version](https://img.shields.io/npm/v/@ab-tag/n8n-openapi-node.svg)](https://www.npmjs.com/package/@ab-tag/n8n-openapi-node)\n[![Patreon](https://img.shields.io/badge/Patreon/ABTag-Support%20Development-6f42c1?logo=patreon&logoColor=white)](https://patreon.com/ABTag)\n\n---\n\n<!-- toc -->\n\n  * [🚀 Help Build This Project](#%F0%9F%9A%80-help-build-this-project)\n- [Use Cases](#use-cases)\n- [Quick Start](#quick-start)\n  * [CLI](#cli)\n- [Advanced Usage](#advanced-usage)\n  * [Installation](#installation)\n  * [How it works](#how-it-works)\n    + [Resource](#resource)\n    + [Operation](#operation)\n    + [Query Parameters](#query-parameters)\n    + [Request Body](#request-body)\n  * [Headers](#headers)\n    + [Fields](#fields)\n- [FAQ](#faq)\n  * [I have only OpenAPI v2 spec, what can I do?](#i-have-only-openapi-v2-spec-what-can-i-do)\n  * [I have openapi.yaml spec, what can I do?](#i-have-openapiyaml-spec-what-can-i-do)\n  * [How to set up credentials from OpenAPI v3 spec?](#how-to-set-up-credentials-from-openapi-v3-spec)\n  * [Why it doesn't work with my OpenAPI spec?](#why-it-doesnt-work-with-my-openapi-spec)\n\n<!-- tocstop -->\n\n## 🚀 Help Build This Project\n\nIf this project saves you time or helps in production, consider supporting its development 🙌\n\n**Your support helps ship features faster and keep the project stable.** 💪\n\n- [https://patreon.com/ABTag](https://patreon.com/ABTag)\n\n# Use Cases\n\nHere's n8n community nodes **generated from OpenAPI** specifications you can use for reference:\n\n- [@ab-tag/n8n-nodes-petstore](https://github.com/ab-tag/n8n-nodes-petstore) - Petstore example generated from\n  [Petstore openapi.json](https://github.com/OAI/OpenAPI-Specification/blob/main/examples/v3.0/petstore.yaml)\n- [@ab-tag/n8n-nodes-chatwoot](https://github.com/ab-tag/n8n-nodes-chatwoot) - ChatWoot n8n community node\n  from\n  [https://www.chatwoot.com/developers/api/](https://www.chatwoot.com/developers/api/). Defines credentials as well (\n  manually)\n\n# Quick Start\n\nIf you have OpenAPI specification - you can easily in few minutes create\n[your community node](https://docs.n8n.io/integrations/community-nodes/usage/) for **n8n**!\n\nIt'll still require to create and publish `n8n-nodes-<yourproject>` npm package,\nbut you can use this package to generate most of the code.\n\n## CLI\n\nUse the interactive CLI to generate node properties:\n\n```bash\nnpx @ab-tag/n8n-openapi-node\n```\n\n👉 We recommend using one of repo for the `n8n-nodes-<yourproject>` package:\n\n- https://github.com/ab-tag/n8n-nodes-petstore - Petstore example generated from OpenAPI v3 spec\n- https://github.com/n8n-io/n8n-nodes-starter - Official n8n nodes starter template\n\nFind more real-world examples in [Use Cases](#use-cases) section.\n\n\n# Advanced Usage\n\n## Installation\n\nAdd `@ab-tag/n8n-openapi-node` as dependency\n\n```bash\nnpm install @ab-tag/n8n-openapi-node\n# OR\npnpm add @ab-tag/n8n-openapi-node\n# OR\nyarn add @ab-tag/n8n-openapi-node\n```\n\n1. Add your `openapi.json` to `src/{NodeName}` folder\n   (use **OpenAPI v3** and **json**, see [FAQ](#faq) if you don't have it)\n\n2. Get your `Node.properties` from OpenAPI v3 spec:\n\n```typescript\nimport {INodeType, INodeTypeDescription, NodeConnectionType} from 'n8n-workflow';\nimport {N8NPropertiesBuilder, N8NPropertiesBuilderConfig} from '@ab-tag/n8n-openapi-node';\nimport * as doc from './openapi.json'; // <=== Your OpenAPI v3 spec\n\nconst config: N8NPropertiesBuilderConfig = {}\nconst parser = new N8NPropertiesBuilder(doc, config);\nconst properties = parser.build()\n\nexport class Petstore implements INodeType {\n  description: INodeTypeDescription = {\n    displayName: 'Petstore',\n    name: 'petstore',\n    icon: 'file:petstore.svg',\n    group: ['transform'],\n    version: 1,\n    subtitle: '={{$parameter[\"operation\"] + \": \" + $parameter[\"resource\"]}}',\n    description: 'Interact with Petstore API',\n    defaults: {\n      name: 'Petstore',\n    },\n    inputs: [NodeConnectionType.Main],\n    outputs: [NodeConnectionType.Main],\n    credentials: [\n      {\n        name: 'petstoreApi',\n        required: false,\n      },\n    ],\n    requestDefaults: {\n      headers: {\n        Accept: 'application/json',\n        'Content-Type': 'application/json',\n      },\n      baseURL: '={{$credentials.url}}',\n    },\n    properties: properties, // <==== HERE\n  };\n}\n```\n\n## How it works\n\n`N8NPropertiesBuilder` extracts few entities from OpenAPI v3 to your n8n community node:\n\n1. **Resource** - a list of **Tags** from OpenAPI spec\n2. **Operation** - a list of **Operations** from OpenAPI spec (aka **Actions** in n8n)\n3. **Query Parameters** - a list of `operation.parameters` from OpenAPI spec\n4. **Request Body** - a list of `operation.requestBody.content` from OpenAPI spec (only for `application/json`)\n5. **Headers** - a list of `operation.parameters` from OpenAPI spec\n\n\n### Resource\n👉 By default, it get **Tags** from OpenAPI spec and converts them to **Resource** in n8n.\n\nYou can override the way how to extract **Resource** from **OpenAPI Tag** defining your custom `IResourceParser`:\n\n```typescript\nimport {IResourceParser} from '@ab-tag/n8n-openapi-node';\n\nexport class CustomResourceParser {\n  CUSTOM_DESCRIPTION = {\n    \"cats\": \"Cats are cute\",\n  }\n\n  name(tag: OpenAPIV3.TagObject): string {\n    // Your custom logic here\n    if (tag['X-Visible-Name']) {\n      return tag['X-Visible-Name'];\n    }\n    return lodash.startCase(tag.name);\n  }\n\n  value(tag: Pick<OpenAPIV3.TagObject, \"name\">): string {\n    // Remove all non-alphanumeric characters\n    const name = tag.name.replace(/[^a-zA-Z0-9_-]/g, '')\n    return lodash.startCase(name)\n  }\n\n  description(tag: OpenAPIV3.TagObject): string {\n    // Your custom logic here\n    return this.CUSTOM_DESCRIPTION[tag.name] || tag.description || '';\n  }\n}\n```\n\nAlternatively, you can use `DefaultResourceParser` and override only the methods you need.\nThe default implementation you can find in [src/ResourceParser.ts](src/ResourceParser.ts)\n\n```typescript\nimport {OpenAPIV3} from 'openapi-types';\nimport * as lodash from 'lodash';\nimport {DefaultResourceParser} from '@ab-tag/n8n-openapi-node';\n\nexport class CustomResourceParser extends DefaultResourceParser {\n  value(tag: OpenAPIV3.TagObject): string {\n    return lodash.startCase(tag.name.replace(/[^a-zA-Z0-9_-]/g, ''));\n  }\n}\n```\n\nThen you use it in `N8NPropertiesBuilder` in `config.resource`:\n\n```typescript\nimport {N8NPropertiesBuilder, N8NPropertiesBuilderConfig} from '@ab-tag/n8n-openapi-node';\nimport * as doc from './openapi.json';\n\nimport {CustomResourceParser} from './CustomResourceParser';\n\nconst config: N8NPropertiesBuilderConfig = {\n  resource: new CustomResourceParser()\n}\nconst parser = new N8NPropertiesBuilder(doc, config);\nconst properties = parser.build()\n```\n\n### Operation\n\n👉 By default, it gets **Operations** from OpenAPI spec and converts them to **Actions** in n8n.\n\nYou can override the way how to extract **Operation** from **OpenAPI Operation** defining your custom\n`IOperationParser`:\n\n```typescript\nimport {IOperationParser} from '@ab-tag/n8n-openapi-node';\n\nexport class CustomOperationParser implements IOperationParser {\n  shouldSkip(operation: OpenAPIV3.OperationObject, context: OperationContext): boolean {\n    // By default it skips operation.deprecated\n    // But we can include all operations\n    return false\n  }\n\n  name(operation: OpenAPIV3.OperationObject, context: OperationContext): string {\n    if (operation['X-Visible-Name']) {\n      return operation['X-Visible-Name'];\n    }\n    return lodash.startCase(operation.operationId)\n  }\n\n  value(operation: OpenAPIV3.OperationObject, context: OperationContext): string {\n    return lodash.startCase(operation.operationId)\n  }\n\n  action(operation: OpenAPIV3.OperationObject, context: OperationContext): string {\n    // How operation is displayed in n8n when you select your node (right form)\n    return operation.summary || this.name(operation, context)\n  }\n\n  description(operation: OpenAPIV3.OperationObject, context: OperationContext): string {\n    return operation.description || operation.summary || '';\n  }\n}\n```\n\nAlternatively, you can use `DefaultOperationParser` and override only the methods you need.\nThe default implementation you can find in [src/OperationParser.ts](src/OperationParser.ts)\n\n```typescript\nimport {DefaultOperationParser} from '@ab-tag/n8n-openapi-node';\n\nexport class CustomOperationParser extends DefaultOperationParser {\n  name(operation: OpenAPIV3.OperationObject, context: OperationContext): string {\n    // NestJS add operationId in format CatController_findOne\n    let operationId: string = operation.operationId!!.split('_').slice(1).join('_');\n    if (!operationId) {\n      operationId = operation.operationId as string;\n    }\n    return lodash.startCase(operationId);\n  }\n}\n```\n\nThen you use it in `N8NPropertiesBuilder` in `config.operation`:\n\n```typescript\nimport {N8NPropertiesBuilder, N8NPropertiesBuilderConfig} from '@ab-tag/n8n-openapi-node';\nimport * as doc from './openapi.json';\nimport {CustomOperationParser} from './CustomOperationParser';\n\nconst config: N8NPropertiesBuilderConfig = {\n  operation: new CustomOperationParser()\n}\nconst parser = new N8NPropertiesBuilder(doc, config);\nconst properties = parser.build()\n```\n\n### Query Parameters\n\n👉 It gets `operation.parameters` from OpenAPI spec and converts them to **Query Parameters** in n8n.\n\n### Request Body\n\n👉 It doesn't create the full structure of the request body, only the first level of properties.\n\nSo if you have request body as\n\n```json\n{\n  \"name\": \"string\",\n  \"config\": {\n    \"id\": 0,\n    \"name\": \"string\"\n  }\n}\n```\n\nit creates 2 fields in n8n:\n\n- `name` - with default value `string`\n- `config` - with default value `{\"id\": 0, \"name\": \"string\"}`\n\n## Headers\n\nIt gets `operation.parameters` from OpenAPI spec and converts them to **Headers** in n8n.\n\n### Fields\n\nYou can override some values for fields at the end, when full `properties` are ready.\n\nHere's example how you can override `session` field value (which has `'default'` string default value) to more n8n\nsuitable `=${$json.session}}`:\n\n```typescript\nimport {Override} from '@ab-tag/n8n-openapi-node';\n\nexport const customDefaults: Override[] = [\n  {\n    // Find field by fields matching\n    find: {\n      name: 'session',\n      required: true,\n      type: 'string',\n    },\n    // Replace 'default' field value\n    replace: {\n      default: '={{ $json.session }}',\n    },\n  },\n];\n```\n\nThen you use it in `N8NPropertiesBuilder`:\n\n```typescript\n\nimport {N8NPropertiesBuilder, N8NPropertiesBuilderConfig} from '@ab-tag/n8n-openapi-node';\nimport * as doc from './openapi.json';\nimport {customDefaults} from './customDefaults';\n\nconst parser = new N8NPropertiesBuilder(doc);\nconst properties = parser.build(customDefaults);\n```\n\n# FAQ\n\n## I have only OpenAPI v2 spec, what can I do?\n\nPaste your **OpenAPI 2.0** definition into https://editor.swagger.io and select **Edit > Convert to OpenAPI 3** from the\nmenu.\n\nhttps://stackoverflow.com/a/59749691\n\n## I have openapi.yaml spec, what can I do?\n\nPaste your yaml spec to https://editor.swagger.io and select **File > Save as JSON** from the menu.\n\n## How to set up credentials from OpenAPI v3 spec?\n\nRight now you need to define it manually.\nCheck [ChatWoot node](https://github.com/ab-tag/n8n-nodes-chatwoot)\nfor an example.\n\n## Why it doesn't work with my OpenAPI spec?\n\nOpen [a new issue](https://github.com/ab-tag/n8n-openapi-node/issues) and please attach\nyour openapi.json file and describe the problem (logs are helpful too).","readmeFilename":"README.md","_rev":"1-3a29baceb1e5bb8355eb4d3f93848c9b"}