Connecting a SOAP/XML backend
Use an SDL-first approach to create a GraphQL API for backends with SOAP.
The custom directive @rest
extends to SOAP services through postbody
configuration. In this way, API Connect for GraphQL supports both REST
structures and SOAP protocols. SOAP services vary a lot. Use this tutorial to learn how to use API Connect for GraphQL to create a temperature
converter so you can apply your knowledge to other SOAP services.
Create your schema
Create a file called index.graphql and add the following code to it:
type Query {
conversion (celsius: Float): JSON
@rest (
endpoint: "https://www.w3schools.com/xml/tempconvert.asmx",
method: POST,
postbody: """
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<CelsiusToFahrenheit xmlns="https://www.w3schools.com/xml/">
<Celsius>{{ .Get "celsius" }}</Celsius>
</CelsiusToFahrenheit>
</soap12:Body>
</soap12:Envelope>
"""
headers: [{name:"Content-Type", value: "text/xml"},
{name: "Content-Type", value: "charset=utf-8"}]
transforms: [{pathpattern: "[]", editor:"xml2json"}]
)
}
The code tells API Connect for GraphQL to
make the SOAP call using the @rest
directive. The @rest
directive supports the
following arguments:
endpoint
- connects the GraphQL API to the ASP.NET Web Service filemethod
- defines the HTTP method used, here, it's POSTpostbody
- defines the POST body, you can see how to pass a GraphQL argument into the body of the SOAP message with{{ .Get "celsius" }}
headers
- adds appropriate headers; check with your own SOAP Backend on what headers it needstransforms
- transforms the response from XML to JSON using an editor xml2json (thepathpattern
is always[]
for xml2json)
Deploy your API
Run stepzen start
inside your workspace, and pick an API name.
stepzen start
? What would you like your endpoint to be called? (api/prodding-seastar)
You'll get a message in your terminal confirming successful deployment.
To test, run a command similar to the following.
"https://<your-account-name>.stepzen.net/api/prodding-seastar/__graphql" --header "Authorization: Apikey $(stepzen whoami --apikey)" --header "Content-Type: application/json" --data '{"query": "{conversion (celsius: 20.0)}"}’
You will get a JSON response from your SOAP service with the
CelsiusToFahrenheitResult
result.
{
"data": {
"conversion": {
"Envelope": {
"Body": {
"CelsiusToFahrenheitResponse": {
"CelsiusToFahrenheitResult": "68",
"xmlns": "https://www.w3schools.com/xml/"
}
},
"soap": "http://www.w3.org/2003/05/soap-envelope",
"xsd": "http://www.w3.org/2001/XMLSchema",
"xsi": "http://www.w3.org/2001/XMLSchema-instance"
}
}
}
}
Create GraphQL types with JSON-to-GraphQL
At this point, the entire JSON body is returned. To allow the API user to specify which pieces of data are returned from the query, you will need to add GraphQL types that reflect the structure of the SOAP service. You can manually create GraphQL types, or you can use the JSON-to-GraphQL tool to transform the response into the correct SDL (Schema Definition Language).
To do that, take the JSON response from the preceding section and paste it on the left side of JSON-to-GraphQL. Hit run, and copy the generated SDL into the bottom of your index.graphql file.
Modify your type Query
in your index.graphql
file to return
Envelope as opposed to JSON for the query.
~~conversion (celsius: Float): JSON~~
conversion (celsius: Float): Envelope
Next, add a resultroot: "Envelope"
argument following your
transforms
argument. The resultroot
directive specifies the path that API Connect for GraphQL will use as the root. Your
index.graphql
should look like the following example:
type Query {
conversion (celsius: Float): Envelope
@rest (endpoint: "https://www.w3schools.com/xml/tempconvert.asmx",
method: POST,
postbody: """
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">
<soap12:Body>
<CelsiusToFahrenheit xmlns="https://www.w3schools.com/xml/">
<Celsius>{{ .Get "celsius" }}</Celsius>
</CelsiusToFahrenheit>
</soap12:Body>
</soap12:Envelope>
"""
headers: [{name:"Content-Type", value: "text/xml"},
{name: "Content-Type", value: "charset=utf-8"}],
transforms: [{pathpattern: "[]", editor:"xml2json"}]
resultroot: Envelope
)
}
type CelsiusToFahrenheitResponse {
CelsiusToFahrenheitResult: String
xmlns: String
}
type Body {
CelsiusToFahrenheitResponse: CelsiusToFahrenheitResponse
}
type Envelope {
Body: Body
soap: String
xsd: String
xsi: String
}
type Conversion {
Envelope: Envelope
}
type Data {
conversion: Conversion
}
type Root {
data: Data
}
Run stepzen start
once more, then run a command to verify your updated
response.
"https://public3cad390d353e929b.stepzen.net/api/prodding-seastar/__graphql" --header "Authorization: Apikey $(stepzen whoami --apikey)" --header "Content-Type: application/json" --data '{"query": "{conversion (celsius: 20.0){Body {CelsiusToFahrenheitResponse {CelsiusToFahrenheitResult}}}}"}'
You now have a GraphQL endpoint where you can select any field from the XML response via your GraphQL request.
{
"data": {
"conversion": {
"Body": {
"CelsiusToFahrenheitResponse": {
"CelsiusToFahrenheitResult": "68"
}
}
}
}
}