{"id":15941,"library":"wsdl-tsclient","title":"WSDL TypeScript Client Generator","description":"wsdl-tsclient is a utility for generating TypeScript SOAP clients and type definitions from WSDL (Web Services Description Language) files. It serves as a bridge between legacy SOAP services and modern TypeScript applications, offering compile-time safety and improved developer experience when interacting with SOAP APIs. The current stable version is 1.7.1. It maintains a consistent release cadence with minor versions introducing new features and bug fixes, indicated by recent releases like 1.7.0 and 1.7.1. Key differentiators include its reliance on `ts-morph` for robust code generation and `node-soap` for runtime client functionality, drawing inspiration from Java's `wsimport` and `openapi-generator`. This tool is particularly useful for projects needing to consume SOAP services with strong typing, without the complexity of manual type definition. It focuses purely on client and type generation, unlike some alternatives that offer OpenAPI conversion or REST gateway scaffolding.","status":"active","version":"1.7.1","language":"javascript","source_language":"en","source_url":"https://github.com/dderevjanik/wsdl-tsclient","tags":["javascript","soap","soap-client","wsdl","wsdl-client","typescript"],"install":[{"cmd":"npm install wsdl-tsclient","lang":"bash","label":"npm"},{"cmd":"yarn add wsdl-tsclient","lang":"bash","label":"yarn"},{"cmd":"pnpm add wsdl-tsclient","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Required as a runtime dependency for the generated SOAP client to make actual web service calls. wsdl-tsclient generates the types and client wrapper, but `node-soap` handles the underlying SOAP protocol communication.","package":"soap","optional":false}],"imports":[{"note":"While CommonJS `require` might work in some Node.js environments due to `esModuleInterop` in `tsconfig.json`, explicit ESM `import` is the recommended and modern approach for this TypeScript-first library.","wrong":"const { generateClient } = require('wsdl-tsclient');","symbol":"generateClient","correct":"import { generateClient } from 'wsdl-tsclient';"},{"note":"This import is for the *generated* client code. If you use the `--esm` CLI flag (available since v1.7.1) for generation, the output imports will include `.js` suffixes. Without it, standard ESM imports are assumed. The `wrong` example shows CommonJS which would fail if the generated code is truly ESM.","wrong":"const { createClientAsync } = require('./generated/MyWsdl');","symbol":"createClientAsync","correct":"import { createClientAsync } from './generated/MyWsdl';"},{"note":"This is an example of importing a generated TypeScript interface for a specific service port, often used for type-checking or mocking. The exact path depends on the WSDL structure and generated file names. The generated files are typically TypeScript and best consumed via `import`.","symbol":"MyServicePort","correct":"import { IMyServicePort } from './generated/MyWsdl/MyServicePort';"}],"quickstart":{"code":"import { generateClient } from 'wsdl-tsclient';\nimport { createClientAsync } from './generated/MyService'; // This path will vary based on your WSDL\nimport * as path from 'path';\nimport * as fs from 'fs';\n\nasync function runGenerationAndClient() {\n  const wsdlPath = path.resolve(__dirname, 'resources', 'MyService.wsdl');\n  const outputPath = path.resolve(__dirname, 'generated');\n\n  // Ensure output directory exists\n  if (!fs.existsSync(outputPath)) {\n    fs.mkdirSync(outputPath, { recursive: true });\n  }\n\n  // Placeholder WSDL content for demonstration\n  // In a real scenario, you'd have a physical WSDL file.\n  const dummyWsdlContent = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<definitions name=\"MyService\" targetNamespace=\"http://www.example.org/MyService/\" xmlns=\"http://schemas.xmlsoap.org/wsdl/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\">\n  <types>\n    <xsd:schema targetNamespace=\"http://www.example.org/MyService/\">\n      <xsd:element name=\"SayHelloRequest\">\n        <xsd:complexType>\n          <xsd:sequence>\n            <xsd:element name=\"name\" type=\"xsd:string\"/>\n          </xsd:sequence>\n        </xsd:complexType>\n      </xsd:element>\n      <xsd:element name=\"SayHelloResponse\">\n        <xsd:complexType>\n          <xsd:sequence>\n            <xsd:element name=\"greeting\" type=\"xsd:string\"/>\n          </xsd:sequence>\n        </xsd:complexType>\n      </xsd:element>\n    </xsd:schema>\n  </types>\n  <message name=\"SayHelloRequest\">\n    <part name=\"parameters\" element=\"tns:SayHelloRequest\"/>\n  </message>\n  <message name=\"SayHelloResponse\">\n    <part name=\"parameters\" element=\"tns:SayHelloResponse\"/>\n  </message>\n  <portType name=\"MyService\">\n    <operation name=\"SayHello\">\n      <input message=\"tns:SayHelloRequest\"/>\n      <output message=\"tns:SayHelloResponse\"/>\n    </operation>\n  </portType>\n  <binding name=\"MyServiceSOAP\" type=\"tns:MyService\">\n    <soap:binding style=\"document\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n    <operation name=\"SayHello\">\n      <soap:operation soapAction=\"http://www.example.org/MyService/SayHello\"/>\n      <input>\n        <soap:body use=\"literal\"/>\n      </input>\n      <output>\n        <soap:body use=\"literal\"/>\n      </output>\n    </operation>\n  </binding>\n  <service name=\"MyService\">\n    <port name=\"MyServiceSOAP\" binding=\"tns:MyServiceSOAP\">\n      <soap:address location=\"http://localhost:8000/MyService\"/>\n    </port>\n  </service>\n</definitions>`;\n\n  // Save dummy WSDL for generation\n  const resourcesDir = path.resolve(__dirname, 'resources');\n  if (!fs.existsSync(resourcesDir)) {\n    fs.mkdirSync(resourcesDir, { recursive: true });\n  }\n  fs.writeFileSync(wsdlPath, dummyWsdlContent);\n\n  console.log(`Generating client from ${wsdlPath} to ${outputPath}...`);\n  await generateClient(wsdlPath, outputPath);\n  console.log('Client generated successfully!');\n\n  // Example of using the generated client (requires 'soap' package to be installed)\n  // In a real scenario, the 'soap' client would be configured to hit a live endpoint.\n  try {\n    const client = await createClientAsync(wsdlPath);\n    // Assuming the generated client has a 'MyService' service and 'MyServiceSOAP' port\n    const result = await client.MyService.MyServiceSOAP.SayHelloAsync({ name: 'World' });\n    console.log('SOAP Call Result:', result[0].greeting); // result[0] typically holds the response body\n  } catch (error) {\n    console.error('Error using generated client (ensure soap is installed and service is running):', error.message);\n  }\n}\n\nrunGenerationAndClient().catch(console.error);\n","lang":"typescript","description":"This example demonstrates how to programmatically generate a TypeScript SOAP client from a WSDL file and then use the generated client to make a call to a (mocked) SOAP service. It includes setup for a dummy WSDL and output directory."},"warnings":[{"fix":"Ensure `npm i soap` or `yarn add soap` is executed in your project where the generated client is consumed.","message":"The `soap` package, which is essential for the runtime functionality of the generated clients, is a peer dependency and must be installed manually alongside `wsdl-tsclient`. Forgetting to install `soap` will lead to runtime errors when attempting to use the generated client.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Upgrade `wsdl-tsclient` to v1.6.0 or newer and ensure your `soap` dependency is `^1.0.0` or a more recent compatible version.","message":"Older versions of `soap` (specifically before `^1.0.0`) had tighter constraints, which could cause issues. Version 1.6.0 of `wsdl-tsclient` relaxed these constraints, but it's important to use a compatible version of `soap` (preferably `^1.0.0` or newer) for stability.","severity":"breaking","affected_versions":"<1.6.0"},{"fix":"Review generated `any` types for critical data structures and consider manual type refinement if strict type safety is paramount in those specific recursive parts.","message":"When WSDL definitions contain self-recursive or cyclic types, `wsdl-tsclient` might generate `any` types to prevent infinite recursion, potentially losing some type safety in those specific areas. This behavior was introduced to handle complex WSDLs more gracefully.","severity":"gotcha","affected_versions":">=1.1.3"},{"fix":"If targeting ESM-only environments, ensure you use `wsdl-tsclient --esm ...` when generating your client code.","message":"The `--esm` CLI flag, introduced in v1.7.1, affects how imports are generated in the client code, specifically by adding `.js` suffixes to import paths for better ESM compatibility. Failing to use this flag for projects targeting pure ESM environments might lead to import resolution issues.","severity":"gotcha","affected_versions":">=1.7.1"},{"fix":"Adjust the `--maxRecursiveDefinitionName` CLI option if you encounter errors related to excessive recursive definition names, or refine your WSDL to reduce name collisions.","message":"WSDL definitions with identical names but different structures can lead to definition collisions. The `--maxRecursiveDefinitionName` option (since v1.2.0) sets a limit on how many times a suffix is added to disambiguate such names. Exceeding this limit will result in an error.","severity":"gotcha","affected_versions":">=1.2.0"},{"fix":"Upgrade `wsdl-tsclient` to version 1.3.1 or later to benefit from improved code generation accuracy for attributes and name casing.","message":"Early versions (before 1.3.1) had issues with generated types missing attributes or having incorrect casing, leading to mismatches with the actual SOAP payload. This could cause runtime failures or incorrect data interpretation.","severity":"gotcha","affected_versions":"<1.3.1"}],"env_vars":null,"last_verified":"2026-04-21T00:00:00.000Z","next_check":"2026-07-20T00:00:00.000Z","problems":[{"fix":"Run `npm install soap` or `yarn add soap` in your project's root directory.","cause":"The `soap` package, which provides the `createClientAsync` function at runtime, is not installed as a dependency in the project using the generated client.","error":"TypeError: createClientAsync is not a function"},{"fix":"Try increasing the limit with the `--maxRecursiveDefinitionName` CLI option (e.g., `wsdl-tsclient ... --maxRecursiveDefinitionName 128`), or consider simplifying the WSDL schema if possible.","cause":"The WSDL contains highly recursive type definitions or many types with very similar names, and `wsdl-tsclient` has reached its limit for creating unique, suffixed names.","error":"Error: Maximum recursive definition name exceeded. This can lead to very long filenames."},{"fix":"Ensure `soap` is installed (`npm i soap`) and, if using TypeScript, that `@types/soap` (if available and needed for an older `soap` version, though `soap` itself often ships types now) is also installed or that `skipLibCheck` is enabled in `tsconfig.json` if type errors persist.","cause":"TypeScript cannot resolve the `soap` module. This usually means `soap` is not installed, or type declarations for `soap` are missing or not correctly configured in `tsconfig.json`.","error":"Cannot find module 'soap' or its corresponding type declarations."},{"fix":"If the generated client is intended for ESM, ensure your `package.json` includes `\"type\": \"module\"` or use a bundler/transpiler configured for ESM. If targeting CommonJS, avoid the `--esm` flag during generation or ensure your Node.js environment correctly handles ESM interoperability.","cause":"You are trying to run a generated client file (or `wsdl-tsclient` itself) that uses ESM `import` statements in a CommonJS-only Node.js environment without proper configuration (e.g., missing `\"type\": \"module\"` in `package.json` for ESM output, or not transpiling to CJS). This is particularly relevant if `--esm` flag was used during generation.","error":"SyntaxError: Cannot use import statement outside a module"}],"ecosystem":"npm"}