Skip to content

Commit

Permalink
feat(soap): auto detection of SOAP namespace, and allow to customize …
Browse files Browse the repository at this point in the history
…it (#8414)

* feat(soap): auto detection of SOAP namespace, and allow to customize it

* Fix CI

* Changeset

* Fallback

* Update packages/transports/soap/src/executor.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
ardatan and coderabbitai[bot] authored Feb 23, 2025
1 parent 03dd5ed commit d9cf1d3
Show file tree
Hide file tree
Showing 19 changed files with 211 additions and 69 deletions.
29 changes: 29 additions & 0 deletions .changeset/tangy-moons-post.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
'@graphql-mesh/transport-soap': minor
'@omnigraph/soap': minor
'@graphql-mesh/soap': minor
'@graphql-mesh/types': patch
---

Auto detection of SOAP version to decide SOAP namespace;
For SOAP 1.1, it is set to `http://schemas.xmlsoap.org/soap/envelope/` and for SOAP 1.2, it is set to `http://www.w3.org/2003/05/soap-envelope`.

If you want to use a custom namespace, you can set it like below;

```ts
import { defineConfig } from '@graphql-mesh/compose-cli'
import { loadSOAPSubgraph } from '@omnigraph/soap'

export const composeConfig = defineConfig({
subgraphs: [
{
sourceHandler: loadSOAPSubgraph('CountryInfo', {
source:
'http://webservices.oorsprong.org/websamples.countryinfo/CountryInfoService.wso?WSDL',
soapNamespace: 'http://foo.com/schemas/soap/envelope'
})
}
]
})
```

10 changes: 10 additions & 0 deletions e2e/soap-demo/__snapshots__/soap-demo.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ directive @soap(
bodyAlias: String
soapHeaders: SOAPHeaders
soapAction: String
soapNamespace: String
) repeatable on FIELD_DEFINITION
directive @extraSchemaDefinitionDirective(directives: _DirectiveExtensions) repeatable on OBJECT
Expand Down Expand Up @@ -121,34 +122,39 @@ type Query @extraSchemaDefinitionDirective(directives: {transport: [{kind: "soap
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.FindPerson"
)
s0_SOAPDemo_SOAPDemoSoap_GetByName(GetByName: s0_GetByName_Input = {}) : s0_GetByNameResponse @soap(
elementName: "GetByNameResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.GetByName"
)
s0_SOAPDemo_SOAPDemoSoap_GetDataSetByName(GetDataSetByName: s0_GetDataSetByName_Input = {}) : s0_GetDataSetByNameResponse @soap(
elementName: "GetDataSetByNameResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.GetDataSetByName"
)
s0_SOAPDemo_SOAPDemoSoap_GetListByName(GetListByName: s0_GetListByName_Input = {}) : s0_GetListByNameResponse @soap(
elementName: "GetListByNameResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.GetListByName"
)
s0_SOAPDemo_SOAPDemoSoap_QueryByName(QueryByName: s0_QueryByName_Input = {}) : s0_QueryByNameResponse @soap(
elementName: "QueryByNameResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.QueryByName"
)
}
Expand Down Expand Up @@ -234,27 +240,31 @@ type Mutation @join__type(graph: SOAP_DEMO) {
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.AddInteger"
)
s0_SOAPDemo_SOAPDemoSoap_DivideInteger(DivideInteger: s0_DivideInteger_Input = {}) : s0_DivideIntegerResponse @soap(
elementName: "DivideIntegerResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.DivideInteger"
)
s0_SOAPDemo_SOAPDemoSoap_LookupCity(LookupCity: s0_LookupCity_Input = {}) : s0_LookupCityResponse @soap(
elementName: "LookupCityResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.LookupCity"
)
s0_SOAPDemo_SOAPDemoSoap_Mission(Mission: JSON = "") : s0_MissionResponse @soap(
elementName: "MissionResponse"
bindingNamespace: "http://tempuri.org"
endpoint: "http://localhost:<soap-demo_port>/csp/samples/SOAP.Demo.cls"
subgraph: "soap-demo"
soapNamespace: "http://schemas.xmlsoap.org/soap/envelope/"
soapAction: "http://tempuri.org/SOAP.Demo.Mission"
)
}
Expand Down
43 changes: 23 additions & 20 deletions examples/soap-demo/tests__bak/soap-demo.test.ts.bak
Original file line number Diff line number Diff line change
@@ -1,37 +1,40 @@
import { basename, join } from 'path';
import { lexicographicSortSchema } from 'graphql';
import { findAndParseConfig } from '@graphql-mesh/cli';
import { getMesh } from '@graphql-mesh/runtime';
import { ProcessedConfig } from '@graphql-mesh/config';
import { getMesh, MeshInstance } from '@graphql-mesh/runtime';
import { InMemoryStoreStorageAdapter, MeshStore } from '@graphql-mesh/store';
import { printSchemaWithDirectives } from '@graphql-tools/utils';

const store = new MeshStore('soap', new InMemoryStoreStorageAdapter(), {
readonly: false,
validate: false,
});

const config$ = findAndParseConfig({
dir: join(__dirname, '..'),
store,
});
const mesh$ = config$.then(config => getMesh(config));
jest.setTimeout(30000);
import { inspect } from 'util';

describe('SOAP Demo', () => {
let mesh: MeshInstance;
let config: ProcessedConfig;
beforeAll(async () => {
const store = new MeshStore('soap', new InMemoryStoreStorageAdapter(), {
readonly: false,
validate: false,
});
config = await findAndParseConfig({
dir: join(__dirname, '..'),
store,
});
mesh = await getMesh(config);
});
it('should generate correct schema', async () => {
const { schema } = await mesh$;
expect(printSchemaWithDirectives(lexicographicSortSchema(schema))).toMatchSnapshot(
expect(printSchemaWithDirectives(lexicographicSortSchema(mesh.schema))).toMatchSnapshot(
'soap-demo-schema',
);
});
it('should give correct response for example queries', async () => {
const { documents } = await config$;
const { execute } = await mesh$;
for (const source of documents) {
const result = await execute(source.document);
for (const source of config.documents) {
if (!source.document || !source.location) {
throw new Error(`Invalid document config: ${inspect(source)}`);
}
const result = await mesh.execute(source.document);
expect(result.errors).toBeUndefined();
expect(result).toMatchSnapshot(basename(source.location) + '-soap-demo-result');
}
});
afterAll(() => mesh$.then(mesh => mesh.destroy()));
afterAll(() => mesh?.destroy?.());
});
7 changes: 7 additions & 0 deletions packages/legacy/handlers/soap/yaml-config.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ type SoapHandler @md {
SOAP Headers to be added to the request
"""
soapHeaders: SOAPHeaders
"""
The namespace of the SOAP envelope
By default, SOAP handler detects the SOAP version and if SOAP version is 1.1,
it uses `http://schemas.xmlsoap.org/soap/envelope/` namespace
If SOAP version is 1.2, it uses `http://www.w3.org/2003/05/soap-envelope` namespace
"""
soapNamespace: String
}

type SOAPHeaders {
Expand Down
4 changes: 4 additions & 0 deletions packages/legacy/types/src/config-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -3069,6 +3069,10 @@
"soapHeaders": {
"$ref": "#/definitions/SOAPHeaders",
"description": "SOAP Headers to be added to the request"
},
"soapNamespace": {
"type": "string",
"description": "The namespace of the SOAP envelope\nBy default, SOAP handler detects the SOAP version and if SOAP version is 1.1,\nit uses `http://schemas.xmlsoap.org/soap/envelope/` namespace\nIf SOAP version is 1.2, it uses `http://www.w3.org/2003/05/soap-envelope` namespace"
}
},
"required": ["source"]
Expand Down
7 changes: 7 additions & 0 deletions packages/legacy/types/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,13 @@ export interface SoapHandler {
*/
bodyAlias?: string;
soapHeaders?: SOAPHeaders;
/**
* The namespace of the SOAP envelope
* By default, SOAP handler detects the SOAP version and if SOAP version is 1.1,
* it uses `http://schemas.xmlsoap.org/soap/envelope/` namespace
* If SOAP version is 1.2, it uses `http://www.w3.org/2003/05/soap-envelope` namespace
*/
soapNamespace?: string;
}
/**
* SOAP Headers to be added to the request
Expand Down
10 changes: 10 additions & 0 deletions packages/loaders/soap/src/SOAPLoader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export interface SOAPLoaderOptions {
endpoint?: string;
cwd?: string;
bodyAlias?: string;
soapNamespace?: string;
}

export interface SOAPHeaders {
Expand Down Expand Up @@ -142,6 +143,9 @@ const soapDirective = new GraphQLDirective({
soapAction: {
type: GraphQLString,
},
soapNamespace: {
type: GraphQLString,
},
},
});

Expand Down Expand Up @@ -196,6 +200,7 @@ export class SOAPLoader {
private cwd: string;
private soapHeaders: SOAPHeaders;
private bodyAlias?: string;
private soapNamespace: string;

constructor(options: SOAPLoaderOptions) {
this.fetchFn = options.fetch || defaultFetchFn;
Expand All @@ -208,6 +213,7 @@ export class SOAPLoader {
this.cwd = options.cwd;
this.soapHeaders = options.soapHeaders;
this.bodyAlias = options.bodyAlias;
this.soapNamespace = 'http://schemas.xmlsoap.org/soap/envelope/';
}

loadXMLSchemaNamespace() {
Expand Down Expand Up @@ -400,6 +406,9 @@ export class SOAPLoader {

async loadDefinition(definition: WSDLDefinition) {
this.getNamespaceDefinitions(definition.attributes.targetNamespace).push(definition);
if (definition.attributes.soap12) {
this.soapNamespace = 'http://www.w3.org/2003/05/soap-envelope';
}
const definitionAliasMap = this.getAliasMapFromAttributes(definition.attributes);
const definitionNamespace = definition.attributes.targetNamespace;
const typePrefix =
Expand Down Expand Up @@ -509,6 +518,7 @@ export class SOAPLoader {
bindingNamespace,
endpoint: this.endpoint,
subgraph: this.subgraphName,
soapNamespace: this.soapNamespace,
};
if (!soapAnnotations.endpoint && portObj.address) {
for (const address of portObj.address) {
Expand Down
7 changes: 7 additions & 0 deletions packages/loaders/soap/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ export interface SOAPSubgraphLoaderOptions {
* @default body
*/
bodyAlias?: string;
/**
* The namespace of the SOAP envelope
* By default, SOAP handler detects the SOAP version and if SOAP version is 1.1,
* it uses `http://schemas.xmlsoap.org/soap/envelope/` namespace
* If SOAP version is 1.2, it uses `http://www.w3.org/2003/05/soap-envelope` namespace
*/
soapNamespace?: string;
}

export function loadSOAPSubgraph(subgraphName: string, options: SOAPSubgraphLoaderOptions) {
Expand Down
1 change: 1 addition & 0 deletions packages/loaders/soap/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export interface WSDLDefinitionAttributes {
name: string;
targetNamespace: string;
soap12?: string;
}

export interface WSDLDefinition {
Expand Down
1 change: 1 addition & 0 deletions packages/loaders/soap/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export interface SoapAnnotations {
elementName: string;
bindingNamespace: string;
endpoint: string;
soapNamespace: string;
bodyAlias?: string;
soapAction?: string;
soapHeaders?: {
Expand Down
Loading

0 comments on commit d9cf1d3

Please sign in to comment.