Validating XML against Schema
In this section you start developing the adapter that the imaginary company New Horizons needs, continuing the case study started in section Example: New Horizons. The adapter will process an XML document with a valid booking, see section New Horizons Requirements for an example. It will write the booking to the database tables “booking” and “visit” you created in section Database Initialization. If you did not do the previous sections, you can
download that work and continue here from your download.
The ingest booking adapter
Before doing something with a booking XML, the ingest booking adapter should check that this document is valid. In this section you will write a first version of the ingest booking adapter that only does that. Please do the following:
The validity of an XML documents is usually checked using an XML schema, see https://www.w3schools.com/xml/schema_intro.asp. Please make a document
NewHorizons/booking.xsdand give it the following contents:
<?xml version="1.0" encoding="UTF-8" ?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="booking"> <xs:complexType> <xs:sequence> <xs:element name="travelerId" type="xs:integer"/> <xs:element name="price" type="money"/> <xs:element name="fee" type="money"/> <xs:element name="destination" minOccurs="1" maxOccurs="unbounded" type="destination" /> </xs:sequence> <xs:attribute name="id" type="xs:integer"></xs:attribute> </xs:complexType> </xs:element> <xs:simpleType name="money"> <xs:restriction base="xs:decimal"> <xs:fractionDigits value="2" /> </xs:restriction> </xs:simpleType> <xs:complexType name="destination"> <xs:all> <xs:element name="price" type="money"/> <xs:element name="startDate" type="xs:date"/> <xs:element name="endDate" type="xs:date"/> </xs:all> <xs:attribute name="hostId" type="xs:integer"/> <xs:attribute name="productId" type="xs:integer"/> </xs:complexType> </xs:schema>
This schema does not check all possible requirements for a booking to be valid. It does not check that the start date of a visit is before its end date. More advanced checks are possible, but then you need features that are new in XML Schema version 1.1. These features are explained at https://www.altova.com/blog/what-s-new-in-xml-schema-11/. The Frank!Framework supports XML Schema 1.1, but you need a commercial text editor to use the new features. With a free text editor, you will not have syntax checking while working on your advanced XSD file.
To have syntax checking with a free text exitor, you have to stick to XML Schema version 1.0. We do so in this tutorial.
Configuration.xmlas shown below:
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../FrankConfig.xsd"> <Adapter name="IngestBooking"> <Receiver name="input"> <ApiListener name="inputListener" uriPattern="booking" method="POST"/> </Receiver> </Adapter> </Configuration>
The adapter starts with a
<Receiver> that contains an
<ApiListener>. The choice for
<ApiListener> makes the adapter listen to REST HTTP requests. The attribute
method="POST" makes it listen to HTTP POST requests. The
uriPattern="booking" attribute defines the relative path to which the adapter listens. The Frank!Framework extends this path to be http://localhost/api/booking.
The Frank!Framework defines a pipe
<XmlValidatorPipe>that checks the incoming message against an XML Schema. We use it in our adapter. Please update
<Configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../FrankConfig.xsd"> <Adapter name="IngestBooking"> <Receiver name="input"> <ApiListener name="inputListener" uriPattern="booking" method="POST"/> </Receiver> <Pipeline firstPipe="checkInput"> <Exits> <Exit name="Exit" state="SUCCESS" code="201" /> <Exit name="BadRequest" state="ERROR" code="400" /> </Exits> <XmlValidatorPipe name="checkInput" root="booking" schema="booking.xsd"> <Forward name="success" path="Exit" /> <Forward name="failure" path="BadRequest" /> </XmlValidatorPipe> </Pipeline> </Adapter> </Configuration>
schema are used to reference the expected root element of the incoming XML and to reference the XML schema file
booking.xsd presented in step 1. A
<Forward> tag links a forward name to a path. On success, we go to the pipeline exit having name
Exit, finishing execution. The
<Pipeline> tag contains an
<Exit> tag that links path
Exit to exit state
SUCCESS and HTTP status code
<XmlValidatorPipe> supports another forward name
failure that is followed when validation fails. It is linked to forward name “BadRequest” at this point, corresponding to exit state
ERROR and code
<XmlValidatorPipe>echos its input message to its output message, both if validation succeeds and if validation fails. We want an error message if we receive an invalid booking message. Please update
... <XmlValidatorPipe name="checkInput" root="booking" schema="booking.xsd"> <Forward name="success" path="Exit" /> <Forward name="failure" path="makeInvalidBookingError" /> </XmlValidatorPipe> <FixedResultPipe name="makeInvalidBookingError" returnString="Input booking does not satisfy booking.xsd"> <Forward name="success" path="BadRequest"/> </FixedResultPipe> </Pipeline> </Adapter> </Configuration>
failure is linked to the pipe named
makeInvalidBookingError. This pipe replaces the incoming message by an error message. The fixed result pipe never fails and follows its (predefined) forward name
success. That forward points to path
Your adapter listens to REST HTTP requests. If you are working under Windows, you can use Postman to send HTTP requests to your adapter. Please do the following:
Install Postman from https://www.getpostman.com/downloads/ if you do not have it.
Press the cog wheen shown in the picture below. It is at the top of the window.
Go to Settings. In the dialog that appears select tab General.
Ensure that “SSL certificate verification” is not checked, see figure below:
Close this dialog.
Press the “New” button shown below. It is almost at the top of the window.
Click “HTTP Request”.
Select method POST (number 1 in the figure below) and type URL
Select tab “Headers” (number1 in the figure below). Add header
Content-Type(number 2) with value
application/xml(number 3) and select it (number 1):
Select tab “Body” (number 1 in the figure below).
Select type “raw” (number 2).
In the message field (number 3), copy/paste the following XML:
<booking id="1"> <travelerId>2</travelerId> <price>500.00</price> <fee>100.00</fee> <destination hostId="3" productId="4"> <price>400.00</price> <startDate>2018-12-27</startDate> <endDate>2019-01-02</endDate> </destination> </booking>
Press “Send” (number 4 in the figure).
The response appears under the request, still in the “Body” tab. It equals the request body. You also see the response code, which is annotated in the figure below.
Under Linux, you can test your adapter as follows:
Copy the valid booking XML listed above (subsection Testing (Windows)) to some file on your computer, say
Execute the following Linux shell command:
curl -i -X POST -H 'Content-Type: application/xml' -d @validBooking.xml http://localhost/api/booking
The output will be something like the following:
HTTP/1.1 201 Created Server: Apache-Coyote/1.1 Last-Modified: Wed, 16 Oct 2019 12:39:06 GMT Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0 Pragma: no-cache Allow: OPTIONS, POST Content-Type: */*;charset=UTF-8 Content-Length: 247 Date: Wed, 16 Oct 2019 12:39:06 GMT <booking id="1"> <travelerId>2</travelerId> <price>500.00</price> <fee>100.00</fee> <destination hostId="3" productId="4"> <price>400.00</price> <startDate>2018-12-27</startDate> <endDate>2019-01-02</endDate> </destination></booking>
The HTTP status code
201 is the
code attribute defined with exit state
SUCCESS. To the bottom, you see that the incoming XML is echoed in the body of the response.
Final remarks (Windows and Linux)
The HTTP request includes a HTTP header
Content-Type: application/xml. You need this header because the ingest booking adapter uses listener
<ApiListener>. Use another listener if you want to omit the header from the request.
The exit name
Exit corresponds to code
201 and state
SUCCESS. This exit state
SUCCESS does not appear in the HTTP response. You can see it if you use the “Test Pipeline” page in the console, see section Testing Pipelines.
Please test your adapter with XML documents that do not satisfy
booking.xsd or with text that is not valid XML. You should see the message
Input booking does not satisfy booking.xsd and HTTP status code
If you are having troubles, you can
download the solution for the work presented so far.