Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 5 commits into from
Feb 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading