Guide: Setting up RDF validation

Track Test bed setup

This guide walks you through the points to consider when setting up validation for RDF and the steps to bring your validation service online. RDF content can be validated through various means; the current guide focuses on validation through SHACL shapes.

What you will achieve

At the end of this guide you will have understood what you need to consider when starting to implement validation services for your RDF vocabulary. You will also have gone through the steps to bring it online and make it available to your users.

An RDF validation service can be created using multiple approaches depending on your needs. You can have an on-premise (or local to your workstation) service through Docker or use the test bed’s resources and, with minimal configuration, bring online a public service that is automatically kept up-to-date.

For the purpose of this guide you will be presented the options to consider and start with a Docker-based instance that could be replaced (or complemented) by a setup through the test bed. Interestingly, the configuration relevant to the validator is the same regardless of the approach you choose to follow.

What you will need

  • About 30 minutes.
  • A text editor.
  • A web browser.
  • Access to the Internet.
  • Docker installed on your machine (only if you want to run the validator as a Docker container).
  • A basic understanding of RDF and SHACL shapes.

How to complete this guide

The steps described in this guide are for the most part hands-on, resulting in you creating a fully operational validation service. For these practical steps there are no prerequisites and the content for all files to be created are provided in each step. In addition, if you choose to try your setup as a Docker container you will also be issuing commands on a command line interface (all commands are provided and explained as you proceed).

Steps

You can complete this guide by following the steps described in this section. Not all steps are required, with certain ones being optional or complementary depending on your needs. The following diagram presents an overview of all steps highlighting the ones that apply in all cases (marked as mandatory):

../_images/step_overview.png

When and why you should skip or consider certain steps depends on your testing needs. Each step’s description covers the options you should consider and the next step(s) to follow depending on your choice.

Step 1: Determine your testing needs

Before proceeding to setup your validator you need to clearly determine your testing needs. A first outline of the approach to follow would be provided by answering the following questions:

  • Will the validator be available to your users as a tool to be used on an ad-hoc basis?
  • Do you plan on measuring the conformance of your community’s members to the RDF-based specification?
  • Is the validator expected to be used in a larger conformance testing context (e.g. during testing of a message exchange protocol)?
  • Should the validator be publicly accessible?
  • Should test data and validation reports be treated as confidential?

The first choice to make is on the type of solution that will be used to power your validation service:

  • Standalone validator: A service allowing validation of individual RDF document instances based on a predefined configuration of SHACL shapes for business rule validation. The service supports fine-grained customisation and configuration of different validation types (e.g. specification versions) and supported communication channels. Importantly, use of the validator is anonymous and it is fully stateless in that none of the test data or validation reports are stored after validation completes.
  • Complete test bed: The test bed is used to realise a full conformance testing campaign. It supports the definition of test scenarios as test cases, organised in test suites that are linked to specifications. Access is account-based allowing users to claim conformance to specifications and execute in a self-service manner their defined test cases. All results are recorded to allow detailed reporting, monitoring and eventually certification. Test cases can address RDF validation but are not limited to that, allowing validation of any complex exchange of information.

It is important to note that these two approaches are by no means exclusive. It is often the case that a standalone validator is defined as a first step that is subsequently used from within test cases in the test bed. The former solution offers a community tool to facilitate work towards compliance supporting ad-hoc data validation, whereas the latter allows for rigorous conformance testing to take place where proof of conformance is required. This could apply in cases where conformance is a qualification criterion before receiving funding or before being accepted as a partner in a distributed system.

Regardless of the choice of solution, the next point to consider will be the type of access. If public access is important then the obvious choice is to allow access over the Internet. An alternative would be an installation that allows access only through a restricted network, be it an organisation’s internal network or a virtual private network accessible only by your community’s members. Finally, an extreme case would be access limited to individual workstations where each community member would be expected to run the service locally (albeit of course without the expectation to test message exchanges with remote parties).

If access to your validation services over the Internet is preferred or at least acceptable, the simplest case is to opt for using the shared ISA² test bed resources, both regarding the standalone validator and the test bed itself. If such access is not acceptable or is technically not possible (e.g. access to private resources is needed), the proposed approach would be to go for a Docker-based on-premise installation of all components.

Summarising the options laid out in this section, you will first want to choose:

  • Whether you will be needing a standalone validator, a complete test bed or both.
  • Whether the validator and/or test bed will be accessible over the Internet or not.

Your choices here can help you better navigate the remaining steps of this guide. Specifically:

Step 2: Prepare validation artefacts

As an example case for RDF validation we will consider a variation of the EU purchase order case first seen in Guide: Creating a test suite. In short, for the purposes of this guide you are considered to be leading an EU cross-border initiative to define a new common specification for the exchange of purchase orders between retailers.

To specify the content of purchase orders your experts have created the following vocabulary:

@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix dc: <http://purl.org/dc/terms/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

<http://itb.ec.europa.eu/sample/po#>
  a owl:Ontology ;
  dc:title "EU Purchase Orders" ;
  dc:description "An example ontology for EU Purchase Orders" .

#
# Classes
#

<http://itb.ec.europa.eu/sample/po#PurchaseOrder>
  a rdfs:Class ;
  rdfs:label "PurchaseOrder"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:subClassOf rdfs:Resource ;
  dc:identifier "po:PurchaseOrder" .

<http://itb.ec.europa.eu/sample/po#Item>
  a rdfs:Class ;
  rdfs:label "Item"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:subClassOf rdfs:Resource ;
  dc:identifier "po:Item" .

#
# PurchaseOrder properties
#

<http://itb.ec.europa.eu/sample/po#shipTo>
  a rdf:Property ;
  rdfs:label "shipTo"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  rdfs:range <http://www.w3.org/ns/locn#Address> ;
  rdfs:subPropertyOf <http://www.w3.org/ns/locn#address> ;
  dc:identifier "po:shipTo" .

<http://itb.ec.europa.eu/sample/po#billTo>
  a rdf:Property ;
  rdfs:label "billTo"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  rdfs:range <http://www.w3.org/ns/locn#Address> ;
  rdfs:subPropertyOf <http://www.w3.org/ns/locn#address> ;
  dc:identifier "po:billTo" .

<http://itb.ec.europa.eu/sample/po#hasItem>
  a rdf:Property ;
  rdfs:label "hasItems"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  rdfs:range <http://itb.ec.europa.eu/sample/po#Item> ;
  dc:identifier "po:hasItem" .

#
# Item properties
#

<http://itb.ec.europa.eu/sample/po#productName>
  a rdf:Property ;
  rdfs:label "productName"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#Item> ;
  rdfs:range rdfs:Literal ;
  dc:identifier "po:productName" .

<http://itb.ec.europa.eu/sample/po#quantity>
  a rdf:Property ;
  rdfs:label "quantity"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#Item> ;
  rdfs:range xsd:positiveInteger ;
  dc:identifier "po:quantity" .

<http://itb.ec.europa.eu/sample/po#price>
  a rdf:Property ;
  rdfs:label "price"@en ;
  rdfs:isDefinedBy <http://itb.ec.europa.eu/sample/po#> ;
  rdfs:domain <http://itb.ec.europa.eu/sample/po#Item> ;
  rdfs:range xsd:decimal ;
  dc:identifier "po:price" .

This vocabulary defines the basic properties for an order’s items (product name, quantity and price in euros) and also a shipping and billing address for which the Core Location Vocabulary has been reused. The syntax used to express the vocabulary in this example is Turtle. You can download this here in the displayed Turtle format or in RDF/XML.

Based on this, a sample purchase order could be expressed in Turtle as follows:

@prefix ns0: <http://www.w3.org/ns/locn#> .
@prefix ns1: <http://itb.ec.europa.eu/sample/po#> .

<http://my.sample.po/po#purchaseOrder>
  a <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  ns1:shipTo <http://my.sample.po/po#home> ;
  ns1:billTo <http://my.sample.po/po#home> ;
  ns1:hasItem <http://my.sample.po/po#item1>;
  ns1:hasItem  <http://my.sample.po/po#item2> .

<http://my.sample.po/po#home>
  a <http://www.w3.org/ns/locn#Address> ;
  ns0:fullAddress "Rue du Test 123, 1000 - Brussels, Belgium" ;
  ns0:thoroughfare "Rue du Test" ;
  ns0:locatorDesignator "123" ;
  ns0:postCode "1000" ;
  ns0:postName "Brussels" ;
  ns0:adminUnitL1 "BE" .

<http://my.sample.po/po#item1>
  a ns1:Item ;
  ns1:productName "Mouse" ;
  ns1:quantity 20 ;
  ns1:priceEUR 15.99 .

<http://my.sample.po/po#item2>
  a ns1:Item ;
  ns1:productName "Keyboard" ;
  ns1:quantity 15 ;
  ns1:priceEUR 25.50 .

Given the inherent flexibility of RDF, your experts have chosen to add certain business rule restrictions as SHACL shapes that would apply to all purchase orders. The implemented rules ensure that:

  • Only a single shipping address is defined.
  • An optional billing address can be defined (the shipping address is considered as the default).
  • An order includes at least one item.
  • All items define their product name, quantity and price.
@prefix po:  <http://itb.ec.europa.eu/sample/po#> .
@prefix locn: <http://www.w3.org/ns/locn#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix sh:  <http://www.w3.org/ns/shacl#> .

#
# Rules for purchase orders
#

po:PurchaseOrderShape
	a sh:NodeShape ;
	sh:targetClass po:PurchaseOrder ;
	sh:property po:shipToShape ;
	sh:property po:billToShape ;
	sh:property po:hasItemsShape .

po:shipToShape
	a sh:PropertyShape ;
	sh:path po:shipTo ;
	sh:minCount 1 ;
	sh:maxCount 1 ;
	sh:class locn:Address ;
	sh:severity sh:Violation .

po:billToShape
	a sh:PropertyShape ;
	sh:path po:billTo ;
	sh:class locn:Address ;
	sh:maxCount 1 ;
	sh:severity sh:Violation .

 po:hasItemsShape
 	a sh:PropertyShape ;
	sh:path po:hasItem ;
	sh:minCount 1 ;
	sh:class po:Item ;
	sh:severity sh:Violation .

#
# Rules for purchase order items
#

po:ItemShape
	a sh:NodeShape ;
	sh:targetClass po:Item ;
	sh:property po:productNameShape ;
	sh:property po:quantityShape ;
	sh:property po:priceShape .

po:productNameShape
	a sh:PropertyShape ;
	sh:path po:productName ;
	sh:minCount 1 ;
	sh:maxCount 1 ;
	sh:nodeKind sh:Literal ;
	sh:severity sh:Violation .

po:quantityShape
	a sh:PropertyShape ;
	sh:path po:quantity ;
	sh:minCount 1 ;
	sh:maxCount 1 ;
	sh:datatype xsd:integer ;
	sh:minExclusive 0 ;
	sh:severity sh:Violation .

po:priceShape
	a sh:PropertyShape ;
	sh:path po:priceEUR ;
	sh:minCount 1 ;
	sh:maxCount 1 ;
	sh:datatype xsd:decimal ;
	sh:severity sh:Violation .

All purchase orders will need to validate against the above SHACL shapes. However, your business requirements also define the concept of a large purchase order which is one that includes more than 10 of each ordered item. To implement this restriction an additional SHACL shape is defined to be considered in addition to the common ones for orders that are supposed to be “large”. Such a SHACL shape file would be as follows:

@prefix po:  <http://itb.ec.europa.eu/sample/po#> .
@prefix sh:  <http://www.w3.org/ns/shacl#> .

#
# Rule for large purchase orders
#

po:LargeItemShape
	a sh:NodeShape ;
	sh:targetClass po:Item ;
	sh:property po:minimumItemsForLargeOrderShape .

po:minimumItemsForLargeOrderShape
	a sh:PropertyShape ;
	sh:path po:quantity ;
	sh:minExclusive 10 ;
	sh:severity sh:Violation .

Given these requirements and validation artefacts we want to support two types of validation (or profiles):

  • basic: For all purchase orders acting as a common base. This is realised by validating against the common SHACL shapes.
  • large: For large purchase orders. This includes validation against the common SHACL shapes and the additional one defined for large orders.

As the first configuration step for the validator we will prepare a folder with the required resources. For this purpose create a root folder named validator with the following subfolders and files:

validator
 |
 +-- resources
      |
      +-- order
           |
           +-- shapes
                |
                +-- PurchaseOrder-common-shapes.ttl
                +-- PurchaseOrder-large-shapes.ttl

You will likely note that we are creating several folders of no obvious use. Nonetheless please follow this structure as it will facilitate subsequent steps where we add resources depending on our needs. In terms of meaning of these folders consider the following:

  • validator is the root folder for all files.
  • resources is the root folder for all files that will be considered by the validator.
  • order is the root folder for all files pertinent to purchase order validation. We separate this as the validator could be used to also validate completely different content.
  • shapes is the folder containing all SHACL shape files.

Regarding the PurchaseOrder-common-shapes.ttl and PurchaseOrder-large-shapes.ttl files you can create them from the above content or download them (here: PurchaseOrder-common-shapes.ttl and PurchaseOrder-large-shapes.ttl). Finally, note that you are free to use any names for the files and folders; the ones used here will however be the ones considered in this guide’s subsequent steps.

Step 3: Prepare validator configuration

After having defined your testing needs and the validation artefacts for your specific case, the next step will be to configure the validator. The validator is defined by a core engine maintained by the test bed team and a layer of configuration, provided by you, that defines its use for a specific scenario. In terms of features the validator supports the following:

  • Validation channels including a REST web service API, a SOAP web service API and a web user interface.
  • Configuration of SHACL shapes to drive the validation that can be local or remote.
  • Definition of different validation types as logically-related sets of validation artefacts.
  • Support per validation type allowing user-provided SHACL shape extensions.
  • Definition of separate validator configurations that are logically split but run as part of a single validator instance. Such configurations are termed “validation domains”.
  • Customisation of all texts presented to users.

Configuration is provided by means of key-value pairs in a property file. This file can be named as you want but needs to end with the .properties extension. In our case we will name this config.properties and place it within the order folder. Recall that the purpose of this folder is to store all resources relevant to purchase order validation. These are the validation artefacts themselves (PurchaseOrder-common-shapes.ttl and PurchaseOrder-large-shapes.ttl) and the configuration file (config.properties).

Define the content of the config.properties file as follows:

# The different types of validation to support. These values are reflected in other properties.
validator.type = basic, large
# Labels to describe the defined types.
validator.typeLabel.basic = Basic purchase order
validator.typeLabel.large = Large purchase order
# Validation artefacts (SHACL shapes) to consider for the "basic" type.
validator.shaclFile.basic = shapes/PurchaseOrder-common-shapes.ttl
# Validation artefacts (SHACL shapes) to consider for the "large" type.
validator.shaclFile.large = shapes/PurchaseOrder-common-shapes.ttl, shapes/PurchaseOrder-large-shapes.ttl
# The title to display for the validator's user interface.
validator.uploadTitle = Purchase Order Validator

All validator properties share a validator. prefix. The validator.type property is key as it defines one or more types of validation that will be supported (multiple are provided as a comma-separated list of values). The values provided here are important not only because they define the available validation types but also because they drive most other configuration properties. Regarding the validation artefacts themselves, these are provided by means of the validator.shaclFile property, specifically:

  • validator.shaclFile.TYPE defines one or more (comma-separated) file paths (relative to the configuration file) to lookup SHACL shape files.
  • validator.shaclFile.TYPE.remote.N can be defined multiple times for SHACL files that are to be loaded remotely (e.g. from a GitHub repository).

Regarding local files (i.e. using the validator.shaclFile.TYPE property) each provided path can be for a file or a folder. If a folder is referenced it will load all contained top-level files (i.e. ignoring subfolders). Regarding remotely loaded files (i.e. the validator.shaclFile.TYPE.remote.N) you may define as many of these as the number of files to load (the N placeholder is a zero-based integer). In addition, for each remotely loaded file we need to also specify its syntax, provided as its mime type. This can be omitted if the syntax can be derived by the file’s extension (e.g. Turtle for .ttl), but it is a good practice to always define this for consistency.

The example that follows illustrates the loading of two remote SHACL shape files for a validation type named v2.2.1 from a remote location:

validator.type = v2.2.1
...
validator.shaclFile.v2.2.1.remote.0.url = https://my.server.com/my_rules_1.ttl
validator.shaclFile.v2.2.1.remote.0.type = text/turtle
validator.shaclFile.v2.2.1.remote.1.url = https://my.server.com/my_rules_2.rdf
validator.shaclFile.v2.2.1.remote.1.type = application/rdf+xml

You may also combine local and remote SHACL shape files by defining a validator.shaclFile.TYPE property and one or more validator.shaclFile.TYPE.remote.N properties. In all cases, the shapes from all sources will be aggregated into a single model for the validation.

Note

Remote SHACL shape caching: Caching is used to avoid constant lookups of remote SHACL shape files. Once loaded, remote SHACL shape files will be automatically refreshed every hour.

In addition, apart from defining the SHACL shapes to apply as local and/or remote files, you may also define for a given validation type whether or not you allow user-provided SHACL shape extensions. this is achieved through the validator.externalShapes property:

...
validator.externalShapes.TYPE = true

Specifying that for a given validation type you allow users to provide SHACL shape extensions will result in any such extensions being combined with your pre-defined SHACL shapes. This could be useful in scenarios where you want to define a common validation base but allow also ad-hoc extensions for e.g. restrictions defined at user-level (e.g. National validation rules to consider in addition to a common set of EU rules).

Note

Generic validator: It is possible to not predefine any SHACL shapes resulting in a validator that is trully generic, expecting all shapes to be provided by users. Such a generic instance actually exists at https://www.itb.ec.europa.eu/shacl/any/upload.

The purpose of the remaining properties is to customise the text descriptions presented to users:

  • validator.typeLabel defines a label to present to users on the validator’s user interface for the type in question.
  • validator.uploadTitle defines the title label to present to users on the validator’s user interface.

Once you have created the config.properties file, the validator folder should be as follows:

validator
 |
 +-- resources
      |
      +-- order
           |
           +-- config.properties
           +-- shapes
                |
                +-- PurchaseOrder-common-shapes.ttl
                +-- PurchaseOrder-large-shapes.ttl

This limited configuration file assumes numerous default configuration properties. An important example is that by default, the validator will expose a web user interface, a SOAP web service API and a REST API. This configuration is driven through the validator.channels property that by default is set to form, rest_api, soap_api (for a user form, REST API and SOAP web service respectively). All configuration properties provided in config.properties relate to the specific domain in question, notably purchase orders, reflected in the validator’s resources as the order folder. Although rarely needed, you may define additional validation domains each with its own set of validation artefacts and configuration file (see Configuring additional validation domains for details on this). Finally, if you are planning to host your own validator instance you can also define configuration at the level of the complete validator (see Additional configuration options regarding application-level configuration options).

For the complete reference of all available configuration properties and their default values refer to section Validator configuration properties.

Step 4: Setup validator as Docker container

Note

When to setup a Docker container: The purpose of setting up your validator as a Docker container is to host it yourself or run it locally on workstations. If you prefer or don’t mind the validator being accessible over the Internet it is simpler to delegate hosting to the test bed team by reusing the test bed’s infrastructure. If this is the case skip this section and go directly to Step 5: Setup validator on test bed. Note however that even if you opt for a validator managed by the test bed, it may still be interesting to create a Docker image for development purposes (e.g. to test new validation artefact versions) or to make available to your users as a complementary service (i.e. use online or download and run locally).

Once the validator’s configuration is ready (configuration file and validation artefacts) you can proceed to create a Docker image.

The configuration for your image is driven by means of a Dockerfile. Create this file in the validator folder with the following contents:

FROM isaitb/shacl-validator:latest
COPY resources /validator/resources/
ENV validator.resourceRoot /validator/resources/

This Dockerfile represents the most simple Docker configuration you can provide for the validator. Let’s analyse each line:

FROM isaitb/shacl-validator:latest This tells Docker that your image will be built over the latest version of the test bed’s isaitb/shacl-validator image. This represents the validator’s core that expects configuration to drive the validation. It is available on the public Docker Hub and as such can be directly used through any Docker installation with Internet access.
COPY resources /validator/resources/ This copies your resources folder to the image under path /validator/resources/.
ENV validator.resourceRoot /validator/resources/ This instructs the validator that it should consider as the root of all its configuration resources the /validator/resources/ folder (which was just copied into it).

The contents of the validator folder should now be as follows:

validator
 |
 +-- Dockerfile
 +-- resources
      |
      +-- order
           |
           +-- config.properties
           +-- shapes
                |
                +-- PurchaseOrder-common-shapes.ttl
                +-- PurchaseOrder-large-shapes.ttl

That’s it. To build the Docker image open a command prompt to the validator folder and issue:

docker build -t po-validator .

This command will create a new local Docker image named po-validator based on the Dockerfile it finds in the current directory. It will proceed to download missing images (e.g. the isaitb/shacl-validator:latest image) and eventually print the following output:

Sending build context to Docker daemon  32.77kB
Step 1/3 : FROM isaitb/shacl-validator:latest
---> 39ccf8d64a50
Step 2/3 : COPY resources /validator/resources/
---> 66b718872b8e
Step 3/3 : ENV validator.resourceRoot /validator/resources/
---> Running in d80d38531e11
Removing intermediate container d80d38531e11
---> 175eebf4f59c
Successfully built 175eebf4f59c
Successfully tagged po-validator:latest

The new po-validator:latest image can now be pushed to a local Docker registry or to the Docker Hub. In our case we will proceed directly to run this as follows:

docker run -d --name po-validator -p 8080:8080 po-validator:latest

This command will create a new container named po-validator based on the po-validator:latest image you just built. It is set to run in the background (-d) and expose its internal listen port through the Docker machine (-p 8080:8080). Note that by default the listen port of the container (which you can map to any available host port) is 8080.

Your validator is now online and ready to validate RDF content. If you want to try it out immediately skip to Step 6: Use the validator. Otherwise, read on to see additional configuration options for the image.

Configuring additional validation domains

Up to this point you have configured validation for purchase orders which defines one or more validation types (basic and large). This configuration can be extended by providing additional types to reflect:

  • Additional profiles with different business rules (e.g. minimal).
  • Specification versions (e.g. basic_v1.0, large_v1.0, basic_v1.1_beta).
  • Other types of content that are linked to purchase orders (e.g. purchase_order_basic_v1.0 and order_receipt_v1.0).

All such extensions would involve defining potentially additional validation artefacts and updating the config.properties file accordingly.

Apart from extending the validation possibilities linked to purchase orders you may want to configure a completely separate validator to address an unrelated specification that would most likely not be aimed to the same user community. To do so you have two options:

  • Repeat the previous steps to define a separate configuration and a separate Docker image. In this case you would be running two separate containers that are fully independent.
  • Reuse your existing validator instance to define a new validation domain. The result will be two validation services that are logically separate but are running as part of a single validator instance.

The rationale behind the second option is simply one of required resources. If you are part of an organisation that needs to support validation for dozens of different RDF-based specifications that are unrelated, it would probably be preferable to have a single application to host rather than one per specification.

In your current single domain setup, the purchase order configuration is reflected through folder order. The name of this folder is also by default assumed to match the name of the domain. A new domain could be named invoice that is linked to RDF-based invoices. This is represented by an invoice folder next to order that contains similarly its validation artefacts and domain-level configuration property file. Considering this new domain, the contents of the validator folder would be as follows:

validator
 |
 +-- Dockerfile
 +-- resources
      |
      +-- invoice
        (Further contents skipped)
      +-- order
        (Further contents skipped)

If you were now to rebuild the validator’s Docker image this would setup two logically-separate validation domains (invoice and order).

Note

Validation domains vs types: In almost all scenarios you should be able to address your validation needs by having a single validation domain with multiple validation types. Validation types under the same domain will all be presented as options for users. Splitting in domains would make sense if you don’t want the users of one domain to see the supported validation types of other domains.

Important: Support for such configuration is only possible if you are defining your own validator as a Docker image. If you plan to use the test bed’s shared validator instance (see Step 5: Setup validator on test bed), your configuration needs to be limited to a single domain. Note of course that if you need additional domains you can in this case simply repeat the configuration process multiple times.

Additional configuration options

We have seen up to now that configuring how validation takes place is achieved through domain-level configuration properties provided in the domain configuration file (file config.properties in our example). When setting up the validator as a Docker image you may also make use of application-level configuration properties to adapt the overall validator’s operation. Such configuration properties are provided as environment variables through ENV directives in the Dockerfile.

We already saw this when defining the validator.resourceRoot property that is the only mandatory property for which no default exists. Other such properties that you may choose to override are:

  • validator.domain: A comma-separated list of names that are to be loaded as the validator’s domains. By default the validator scans the provided validator.resourceRoot folder and selects as domains all subfolders that contain a configuration property file (folder order in our case). You may want to configure the list of folder names to consider if you want to ensure that other folders get ignored.
  • validator.domainName.DOMAIN: A mapping for a domain (replacing the DOMAIN placeholder) that defines the name that should be presented to users. This would be useful if the folder name itself (order in our example) is not appropriate (e.g. if the folder was named files).

The following example Dockerfile illustrates use of these properties. The values set correspond to the applied defaults so the resulting Docker images from this Dockerfile and the original one (see Step 4: Setup validator as Docker container) are in fact identical:

FROM isaitb/shacl-validator:latest
COPY resources /validator/resources/
ENV validator.resourceRoot /validator/resources/
ENV validator.domain order
ENV validator.domainName.order order

See Application-level configuration for the full list of supported application-level properties.

Finally, it may be the case that you need to adapt further configuration properties that relate to how the validator’s application is ran. The validator is built as a Spring Boot application which means that you can override all configuration properties by means of environment variables. This is rarely needed as you can achieve most important configuration through the way you run the Docker container (e.g. defining port mappings). Nonetheless the following adapted Dockerfile shows how you could ensure the validator’s application starts up on another port (9090) and uses a specific context path (/ctx).

FROM isaitb/shacl-validator:latest
COPY resources /validator/resources/
ENV validator.resourceRoot /validator/resources/
ENV server.servlet.context-path /ctx
ENV server.port 9090

Note

Custom port: Even if you define the server.port property to a different value other than the default 8080 this remains internal to the Docker container. The port through which you access the validator will be the one you map on your host through the -p flag of the docker run command.

The full list of such application configuration properties, as well as their default values, are listed in the Spring Boot configuration property documentation.

Step 5: Setup validator on test bed

Note

When to setup on test bed resources: Setting up your validator on the test bed’s resources removes hosting concerns and allows you to benefit from automatic service reloads for configuration changes. In doing so however you need to keep in mind that the validator will be exposed over the Internet. If this approach is not suitable for you (e.g. you want to expose the validator within a restricted network) you should consider setting up the validator as a Docker container (see Step 4: Setup validator as Docker container) that you can then host as you see fit.

To configure a validator using the test bed’s resources all you need to do is get in touch with the test bed team and provide the validator’s configuration. Specifically:

  1. Send an email to DIGIT-ITB@ec.europa.eu describing your case: This step is needed for two reasons. Firstly you may want to have a further discussion and potentially a demo to better understand the available options. Secondly the test bed’s team would need to ensure that you qualify to use its resources (to e.g. avoid that you are a private company planning to offer commercial validation services).
  2. Share the configuration for the validator: Once contact has been established you need to provide the initial configuration for the validator.

Regarding the second step, the validator’s configuration to be shared is the contents of the validator folder as described in Step 3: Prepare validator configuration. The eventual goal here will be to have the configuration available through an accessible Git repository. This can be done in a number of ways listed below in decreasing order of preference:

  • Create a new Git repository: You can push all resources (the validator folder) to a new Git repository (e.g. on GitHub or the European Commission’s CITNet Bitbucket server). You can of course add any other resources to this repository as you see fit (e.g. a README file). Once done provide the repository’s URL to the test bed team.
  • Provide the resources to the test bed team: You can send the configuration files themselves to the test bed’s team (e.g. make an archive of the validator folder). Ideally you should define the configuration file but if in doubt you can simply describe the resources and the test bed team will prepare the initial configuration for you. When following this approach a new Git repository will be created for you on the European Commission’s CITNet Bitbucket server for which you will be assigned write access (assuming you have a CITNet user account).
  • Update an existing Git repository: If you already have a Git repository to maintain the validation artefacts you can reuse this by adding to it the required configuration file (config.properties in our case). When ready you will need to provide the test bed team with the URL to the repository and the location of the configuration file.

Following the initial configuration, the resulting Git repository will be monitored to detect any changes to the validation artefacts or the configuration file. If such a change is detected, the validation service will be automatically updated within a few minutes.

Note

Using a dedicated Git repository for the validator: Whether you define a new Git repository yourself or the test bed team creates one for you, the result is a repository that is dedicated to the validator. This approach is preferable to reusing an existing Git repository to avoid unwanted changes to the validator. whether or not this is done through GitHub, CITNet’s Bitbucket or another service depends on what best suits your needs.

As part of the initial setup for the validator the test bed team will also configure how it is accessed. The name used will match the name of the folder that contains your configuration file (order in the considered example), but this can differ according to your preferences. If this is the case make sure to inform the test bed team of your preferred naming.

Considering our example, for a name of order, the resulting root URL through which the validator will be accessed is https://www.itb.ec.europa.eu/shacl/order. The specific paths will depend on the supported validation channels as described in Step 6: Use the validator.

Step 6: Use the validator

Well done! At this step your validator has been successfully configured and is ready to use. Depending on which approach was followed, this may have been done either:

The validation channels that are supported depend on the configuration you have supplied. This is done through the validator.channels property of your configuration file (config.properties) that defaults to form, rest_api, soap_api. The supported channels are as follows:

  • form: A web user interface allowing a user to provide the RDF content to validate.
  • rest_api: A REST API allowing machine-to-machine integration using HTTP calls.
  • soap_api: A SOAP API allowing contract-based machine-to-machine integration using SOAP web service calls.

The following sub-sections describe how each channel can be used considering the example EU purchase order specification.

Validation via user interface

The validator’s user interface is available at the /shacl/DOMAIN/upload path. The exact path depends on how this is deployed:

The first page that you see is a simple form to provide the RDF content to validate.

../_images/validator_upload.png

This form expects the following input:

  • Content to validate: The RDF content that will be submitted for validation. The preceding dropdown selection determines how this will be provided, specifically as a file input (pre-selected), as a URI to be loaded remotely or as content to be provided using an editor.
  • Validate as: The type of validation to apply.
  • Content syntax: The syntax to consider for the provided content. This may be omitted in case of file upload and URI input if the file’s extension can determine the syntax.

Note that all displayed labels can be adapted through the config.properties configuration file (see Properties related to UI labels). The available validation types match the ones defined in the validator.type property, displayed using the validator.typeLabel.TYPE labels.

../_images/validator_upload_selected.png

It is worth noting also that if your configuration defined only a single validation type, the user interface would be simplified by presenting only the content input controls (i.e. considering the single validation type as pre-selected).

../_images/validator_upload_simple.png

In addition, if your configuration for the selected validation type allows for user-provided SHACL shapes, the form also includes the controls to manage the shape files you provide. Files can be defined via file upload or remote URI, specifying at the same time the syntax to consider if this cannot be determined by its extension (similar to the content to validate).

../_images/validator_upload_external.png

Once you have provided your input click the Upload button to trigger the validation. Upon completion you will be presented with the validation results:

../_images/validator_result.png

This screen includes an overview of the result listing:

  • The validation timestamp (in UTC), the name of the validated file and the applied validation type (if more than one are configured).
  • The overall result (SUCCESS or FAILURE).
  • The number of errors, warnings and information messages.

This section is followed by the Details panel, where the details of each report item are listed:

  • It’s type (whether this is an error, warning or information message).
  • It’s description.
  • It’s location in the provided input in terms of the focus node and its specific path.
  • The test performed in terms of the name of the SHACL rule applied and the value that was tested.

With respect to reporting, apart from the on-screen display, you are also presented with flexible download controls to:

  • Download the validation report in PDF format (selected by default - sample here). You may also select to download the report as a SHACL Validation Report in any of the provided syntaxes (sample in Turtle here).
  • Download the validated content in any of the provided syntaxes.
  • Download the SHACL shapes used for the validation in any of the provided syntaxes. Note that the shapes in this case will be the aggregated shapes from predefined files and user-provided ones (if supported and provided).

Finally, to trigger a new validation you may either use the form from the top of the result screen or click on the form’s title that will take you back to the previous page.

Validation via REST web service API

The validator’s REST API is available under the /shacl/DOMAIN/api path. The exact path depends on how this is deployed:

The operations that the REST API supports are the following:

Operation Description HTTP method Request payload type
info Retrieve the available validation types for a given domain. GET None
validate Validate one RDF instance. POST application/json
validateMultiple Validate multiple RDF instances. POST application/json

The supported operations as well their input and output are thoroughly documented:

  • Using OpenAPI and Swagger, with the documentation available at the /shacl/swagger-ui.html path.
  • Using Hydra where the API entry point is available at the /shacl/DOMAIN/api path.

The Swagger UI is notable as this provides rich, interactive documentation that can also be used to call the underlying operations. To access this navigate to:

../_images/swagger_ui.png

Note that before using the Swagger UI to execute any of the operations you will also need to specify the {domain} path parameter. In the example we have been following this would be order.

Coming back to the specific operations supported, the first one to address is the info operation. This can be useful if the validator is configured with multiple validation types in which case this service returns each type’s name and description.

Considering our order example making a GET request to http://DOCKER_MACHINE:8080/shacl/order/api/info (or https://www.itb.ec.europa.eu/shacl/order/api/info on the test bed), you receive a JSON response as follows:

{
    "domain": "order",
    "validationTypes": [
        {
            "type": "basic",
            "description": "Basic purchase order"
        },
        {
            "type": "large",
            "description": "Large purchase order"
        }
    ]
}

To trigger validation of a RDF instance you use the validate operation by making a POST request of type application/json to http://DOCKER_MACHINE:8080/shacl/order/api/validate (or https://www.itb.ec.europa.eu/shacl/order/api/validate on the test bed). To illustrate how this can be used we will consider a purchase order that will fail validation when checked to be of large type due to it lacking the required quantities per item (you can download the sample here):

@prefix ns0: <http://www.w3.org/ns/locn#> .
@prefix ns1: <http://itb.ec.europa.eu/sample/po#> .

<http://my.sample.po/po#purchaseOrder>
  a <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  ns1:shipTo <http://my.sample.po/po#home> ;
  ns1:billTo <http://my.sample.po/po#home> ;
  ns1:hasItem <http://my.sample.po/po#item1>;
  ns1:hasItem  <http://my.sample.po/po#item2> .

<http://my.sample.po/po#home>
  a <http://www.w3.org/ns/locn#Address> ;
  ns0:fullAddress "Rue du Test 123, 1000 - Brussels, Belgium" ;
  ns0:thoroughfare "Rue du Test" ;
  ns0:locatorDesignator "123" ;
  ns0:postCode "1000" ;
  ns0:postName "Brussels" ;
  ns0:adminUnitL1 "BE" .

<http://my.sample.po/po#item1>
  a ns1:Item ;
  ns1:productName "Mouse" ;
  ns1:quantity 5 ;
  ns1:priceEUR 15.99 .

<http://my.sample.po/po#item2>
  a ns1:Item ;
  ns1:productName "Keyboard" ;
  ns1:quantity 15 ;
  ns1:priceEUR 25.50 .

As a first validation example we will provide the content to validate as a URI to be looked up:

{
    "contentToValidate": "https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl",
    "validationType": "large"
}

In the contentToValidate parameter we include the URI to the file whereas in the validationType parameter we select the desired validation type. Note that we need to define the validation type as we have more than one configured for purchase orders. If there was only one this parameter would be optional.

The response returned for this call will be the SHACL validation report in application/rdf+xml syntax:

<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:po="http://itb.ec.europa.eu/sample/po#"
    xmlns:locn="http://www.w3.org/ns/locn#"
    xmlns:sh="http://www.w3.org/ns/shacl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
    <sh:ValidationReport>
        <sh:conforms rdf:datatype="http://www.w3.org/2001/XMLSchema#boolean">false</sh:conforms>
        <sh:result>
            <sh:ValidationResult>
                <sh:value rdf:datatype="http://www.w3.org/2001/XMLSchema#integer">3</sh:value>
                <sh:resultPath rdf:resource="http://itb.ec.europa.eu/sample/po#quantity"/>
                <sh:resultMessage>Value is not &gt; 10^^http://www.w3.org/2001/XMLSchema#integer</sh:resultMessage>
                <sh:focusNode rdf:resource="http://my.sample.po/po#item2"/>
                <sh:sourceShape rdf:resource="http://itb.ec.europa.eu/sample/po#minimumItemsForLargeOrderShape"/>
                <sh:sourceConstraintComponent rdf:resource="http://www.w3.org/ns/shacl#MinExclusiveConstraintComponent"/>
                <sh:resultSeverity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
            </sh:ValidationResult>
        </sh:result>
    </sh:ValidationReport>
</rdf:RDF>

In this report we can see the overall validation result (false in sh:conforms), as well as the individual report items (one in this case). Each such item includes:

  • The severity of the item (sh:resultSeverity).
  • The message for the item (sh:resultMessage).
  • The location in the validated content that triggered the failure (sh:focusNode and sh:resultPath).
  • The test that was made (the failing shape sh:sourceShape, the constraint type sh:sourceConstraintComponent and the tested value sh:value).

You may request the validation report in different syntaxes by providing as part of the input the reportSyntax property with the desired report mime type. For example, to request the report in Turtle format you would provide:

{
    "contentToValidate": "https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl",
    "validationType": "large",
    "reportSyntax": "text/turtle"
}

Resulting in the same report but this time in Turtle syntax:

@prefix sh:    <http://www.w3.org/ns/shacl#> .
@prefix xsd:   <http://www.w3.org/2001/XMLSchema#> .
@prefix locn:  <http://www.w3.org/ns/locn#> .
@prefix po:    <http://itb.ec.europa.eu/sample/po#> .

[ a            sh:ValidationReport ;
sh:conforms  false ;
sh:result    [ a                             sh:ValidationResult ;
                sh:focusNode                  <http://my.sample.po/po#item2> ;
                sh:resultMessage              "Value is not > 10^^http://www.w3.org/2001/XMLSchema#integer" ;
                sh:resultPath                 po:quantity ;
                sh:resultSeverity             sh:Violation ;
                sh:sourceConstraintComponent  sh:MinExclusiveConstraintComponent ;
                sh:sourceShape                po:minimumItemsForLargeOrderShape ;
                sh:value                      3
            ]
] .

This could also have been achieved by means of an HTTP Accept header sent with the POST request with a value of text/turtle.

Note

Default report syntax: The validation report is returned by default in application/rdf+xml syntax. You may override this as part of your domain configuration (in file config.properties) by setting the validator.defaultReportSyntax property to the desired mime type.

In the previous example we saw validation by passing a reference to a remote resource as a URI. You may also choose to embed the content to be validated within the request itself as a BASE64 encoded string. To do so you set the value of the contentToValidate property to the BASE64 string but also specify the contentSyntax property with the input’s mime type (text/turtle in our case) as this can no longer be determined from the content’s file extension:

{
    "contentToValidate": "QHByZWZpeCBuczA6IDxodHRwOi8vd3d3LnczLm9yZy9ucy9sb2NuIz4gLgpAcHJlZml4IG5zMTogPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KCjxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2hvbWU+CiAgYSA8aHR0cDovL3d3dy53My5vcmcvbnMvbG9jbiNBZGRyZXNzPiA7CiAgbnMwOmZ1bGxBZGRyZXNzICJSdWUgZHUgVGVzdCAxMjMsIDEwMDAgLSBCcnVzc2VscywgQmVsZ2l1bSIgOwogIG5zMDp0aG9yb3VnaGZhcmUgIlJ1ZSBkdSBUZXN0IiA7CiAgbnMwOmxvY2F0b3JEZXNpZ25hdG9yICIxMjMiIDsKICBuczA6cG9zdENvZGUgIjEwMDAiIDsKICBuczA6cG9zdE5hbWUgIkJydXNzZWxzIiA7CiAgbnMwOmFkbWluVW5pdEwxICJCRSIgLgoKPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jcHVyY2hhc2VPcmRlcj4KICBhIDxodHRwOi8vaXRiLmVjLmV1cm9wYS5ldS9zYW1wbGUvcG8jUHVyY2hhc2VPcmRlcj4gOwogIG5zMTpzaGlwVG8gPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jaG9tZT4gOwogIG5zMTpoYXNJdGVtIDxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2l0ZW0xPiA7CiAgbnMxOmhhc0l0ZW0gPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jaXRlbTI+IC4KCjxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2l0ZW0xPgogIGEgbnMxOkl0ZW0gOwogIG5zMTpwcm9kdWN0TmFtZSAiTW91c2UiIDsKICBuczE6cXVhbnRpdHkgMjAgOwogIG5zMTpwcmljZUVVUiAxNS45OSAuCgo8aHR0cDovL215LnNhbXBsZS5wby9wbyNpdGVtMj4KICBhIG5zMTpJdGVtIDsKICBuczE6cHJvZHVjdE5hbWUgIktleWJvYXJkIiA7CiAgbnMxOnF1YW50aXR5IDMgOwogIG5zMTpwcmljZUVVUiAyNS41MCAu",
    "contentSyntax": "text/turtle",
    "validationType": "large"
}

The contentSyntax property can also be provided when the input is a URI although this can be skipped if it can be determined from the referenced file’s extension. Note that in terms of the content to validate you may also specify the embeddingMethod property with a value of either URL or BASE64. The purpose of this is to explicitly define how the contentToValidate value should be interpreted, although this can usually be skipped: If not specified, the content will be checked to see if it is a well-formed URL and if so an embeddingMethod of URL is automatically considered. The following example defines the embeddingMethod property and is equivalent to the previous one:

{
    "contentToValidate": "QHByZWZpeCBuczA6IDxodHRwOi8vd3d3LnczLm9yZy9ucy9sb2NuIz4gLgpAcHJlZml4IG5zMTogPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KCjxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2hvbWU+CiAgYSA8aHR0cDovL3d3dy53My5vcmcvbnMvbG9jbiNBZGRyZXNzPiA7CiAgbnMwOmZ1bGxBZGRyZXNzICJSdWUgZHUgVGVzdCAxMjMsIDEwMDAgLSBCcnVzc2VscywgQmVsZ2l1bSIgOwogIG5zMDp0aG9yb3VnaGZhcmUgIlJ1ZSBkdSBUZXN0IiA7CiAgbnMwOmxvY2F0b3JEZXNpZ25hdG9yICIxMjMiIDsKICBuczA6cG9zdENvZGUgIjEwMDAiIDsKICBuczA6cG9zdE5hbWUgIkJydXNzZWxzIiA7CiAgbnMwOmFkbWluVW5pdEwxICJCRSIgLgoKPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jcHVyY2hhc2VPcmRlcj4KICBhIDxodHRwOi8vaXRiLmVjLmV1cm9wYS5ldS9zYW1wbGUvcG8jUHVyY2hhc2VPcmRlcj4gOwogIG5zMTpzaGlwVG8gPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jaG9tZT4gOwogIG5zMTpoYXNJdGVtIDxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2l0ZW0xPiA7CiAgbnMxOmhhc0l0ZW0gPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jaXRlbTI+IC4KCjxodHRwOi8vbXkuc2FtcGxlLnBvL3BvI2l0ZW0xPgogIGEgbnMxOkl0ZW0gOwogIG5zMTpwcm9kdWN0TmFtZSAiTW91c2UiIDsKICBuczE6cXVhbnRpdHkgMjAgOwogIG5zMTpwcmljZUVVUiAxNS45OSAuCgo8aHR0cDovL215LnNhbXBsZS5wby9wbyNpdGVtMj4KICBhIG5zMTpJdGVtIDsKICBuczE6cHJvZHVjdE5hbWUgIktleWJvYXJkIiA7CiAgbnMxOnF1YW50aXR5IDMgOwogIG5zMTpwcmljZUVVUiAyNS41MCAu",
    "embeddingMethod": "BASE64",
    "contentSyntax": "text/turtle",
    "validationType": "large"
}

Finally, recall that in Step 3: Prepare validator configuration the possibility was mentioned to allow for a given validation type, external SHACL shapes to be provided as part of the validator’s input. To do this through the REST API you would provide a externalRules array containing objects with three properties:

  • ruleSet for the RDF content containing the SHACL shapes to consider.
  • ruleSyntax for the syntax of the ruleSet RDF content.
  • embeddingMethod (URL or BASE64) to determine how the ruleSet value is to be considered, either as a remote reference URL or an embedded BASE64 string.

Similar to the input content, the ruleSyntax can be skipped if the ruleSet value is a URL for a file with a known file extension. Also the embeddingMethod can be skipped to allow the validator to determine it itself.

A sample request specifying an additional set of SHACL shapes is provided below:

{
    "contentToValidate": "https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl",
    "validationType": "large",
    "reportSyntax": "text/turtle",
    "externalRules": [
        {
            "ruleSet": "https://path.to.file/shape_extensions.ttl"
        }
    ]
}

Note

Blocking user-provided extensions: If you provide SHACL shape extensions for a validation type where this has not been explicitly allowed the call will fail.

The remaining operation that is available is validateMultiple that can be used for batch validation. In this case the input to the service uses the same JSON structure but this time as an array. To use the operation submit a POST request of type application/json to http://DOCKER_MACHINE:8080/shacl/order/api/validateMultiple (or https://www.itb.ec.europa.eu/shacl/order/api/validateMultiple on the test bed).

In the following example two distinct validations are requested:

[
    {
        "contentToValidate": "https://www.itb.ec.europa.eu/files/samples/shacl/sample.ttl",
        "validationType": "basic",
        "reportSyntax": "text/turtle"
    },
    {
        "contentToValidate": "https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl",
        "validationType": "large",
        "reportSyntax": "text/turtle"
    }
]

The resulting response in this case always includes the reports as BASE64 encoded strings, specifying the syntax to consider:

[
    {
        "report": "QHByZWZpeCBzaDogICAgPGh0dHA6Ly93d3cudzMub3JnL25zL3NoYWNsIz4gLgpAcHJlZml4IHhzZDogICA8aHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjPiAuCkBwcmVmaXggbnMwOiAgIDxodHRwOi8vd3d3LnczLm9yZy9ucy9sb2NuIz4gLgpAcHJlZml4IGxvY246ICA8aHR0cDovL3d3dy53My5vcmcvbnMvbG9jbiM+IC4KQHByZWZpeCBuczE6ICAgPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KQHByZWZpeCBwbzogICAgPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KClsgYSAgICAgICAgICAgIHNoOlZhbGlkYXRpb25SZXBvcnQgOwogIHNoOmNvbmZvcm1zICB0cnVlCl0gLgo=",
        "reportSyntax": "text/turtle"
    },
    {
        "report": "QHByZWZpeCBzaDogICAgPGh0dHA6Ly93d3cudzMub3JnL25zL3NoYWNsIz4gLgpAcHJlZml4IHhzZDogICA8aHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjPiAuCkBwcmVmaXggbnMwOiAgIDxodHRwOi8vd3d3LnczLm9yZy9ucy9sb2NuIz4gLgpAcHJlZml4IGxvY246ICA8aHR0cDovL3d3dy53My5vcmcvbnMvbG9jbiM+IC4KQHByZWZpeCBuczE6ICAgPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KQHByZWZpeCBwbzogICAgPGh0dHA6Ly9pdGIuZWMuZXVyb3BhLmV1L3NhbXBsZS9wbyM+IC4KClsgYSAgICAgICAgICAgIHNoOlZhbGlkYXRpb25SZXBvcnQgOwogIHNoOmNvbmZvcm1zICBmYWxzZSA7CiAgc2g6cmVzdWx0ICAgIFsgYSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2g6VmFsaWRhdGlvblJlc3VsdCA7CiAgICAgICAgICAgICAgICAgc2g6Zm9jdXNOb2RlICAgICAgICAgICAgICAgICAgPGh0dHA6Ly9teS5zYW1wbGUucG8vcG8jaXRlbTI+IDsKICAgICAgICAgICAgICAgICBzaDpyZXN1bHRNZXNzYWdlICAgICAgICAgICAgICAiVmFsdWUgaXMgbm90ID4gMTBeXmh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI2ludGVnZXIiIDsKICAgICAgICAgICAgICAgICBzaDpyZXN1bHRQYXRoICAgICAgICAgICAgICAgICBwbzpxdWFudGl0eSA7CiAgICAgICAgICAgICAgICAgc2g6cmVzdWx0U2V2ZXJpdHkgICAgICAgICAgICAgc2g6VmlvbGF0aW9uIDsKICAgICAgICAgICAgICAgICBzaDpzb3VyY2VDb25zdHJhaW50Q29tcG9uZW50ICBzaDpNaW5FeGNsdXNpdmVDb25zdHJhaW50Q29tcG9uZW50IDsKICAgICAgICAgICAgICAgICBzaDpzb3VyY2VTaGFwZSAgICAgICAgICAgICAgICBwbzptaW5pbXVtSXRlbXNGb3JMYXJnZU9yZGVyU2hhcGUgOwogICAgICAgICAgICAgICAgIHNoOnZhbHVlICAgICAgICAgICAgICAgICAgICAgIDMKICAgICAgICAgICAgICAgXQpdIC4K",
        "reportSyntax": "text/turtle"
    }
]

Validation via SOAP web service API

The validator’s SOAP API is available under the /shacl/soap path. The exact path depends on how this is deployed (path to WSDL provided):

The SOAP API used is the GITB validation service API, meaning that the validator is a GITB-compliant validation service. The importance of this is that apart from using it directly, this SOAP API allows integration of the validator in more complex conformance testing scenarios as a validation step in GITB TDL test cases. This potential is covered further in Step 7: Use the validator in GITB TDL test cases.

The operations supported are as follows:

  • getModuleDefinition: Called to return information on how to call the service (i.e. what inputs are expected).
  • validate: Called to trigger validation for provided content.

You can download this SOAP UI project that includes sample calls of these operations (make sure to change the service URL to match your setup).

Regarding the getModuleDefinition operation, a request of:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.gitb.com/vs/v1/">
   <soapenv:Header/>
   <soapenv:Body>
      <v1:GetModuleDefinitionRequest/>
   </soapenv:Body>
</soapenv:Envelope>

Will produce a response as follows:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns4:GetModuleDefinitionResponse xmlns:ns2="http://www.gitb.com/core/v1/" xmlns:ns3="http://www.gitb.com/tr/v1/" xmlns:ns4="http://www.gitb.com/vs/v1/">
         <module operation="V" id="ValidatorService">
            <ns2:metadata>
               <ns2:name>ValidatorService</ns2:name>
               <ns2:version>1.0.0</ns2:version>
            </ns2:metadata>
            <ns2:inputs>
               <ns2:param type="binary" name="contentToValidate" use="R" kind="SIMPLE" desc="The content to validate, provided as a string, BASE64 or a URI."/>
               <ns2:param type="string" name="embeddingMethod" use="O" kind="SIMPLE" desc="The embedding method to consider for the 'contentToValidate' input ('BASE64', 'URL' or 'STRING')."/>
               <ns2:param type="string" name="contentSyntax" use="O" kind="SIMPLE" desc="The mime type of the provided content."/>
               <ns2:param type="string" name="validationType" use="O" kind="SIMPLE" desc="The type of validation to perform (if multiple types are supported)."/>
               <ns2:param type="list[map]" name="externalRules" use="O" kind="SIMPLE" desc="A list of maps that defines external SHACL shapes to consider in addition to any preconfigured ones. Each map item corresponds to a SHACL file and defines the following keys: 'ruleSet' (the rules to consider, see 'contentToValidate' for its semantics), 'ruleSyntax' (the syntax of the 'ruleSet' content, see 'contentSyntax' for its semantics), 'embeddingMethod' (the way to consider the 'ruleSet' value)."/>
            </ns2:inputs>
         </module>
      </ns4:GetModuleDefinitionResponse>
   </soap:Body>
</soap:Envelope>

This response can be customised through configuration properties in config.properties to provide descriptions specific to your setup. For example, extending config.properties with the following:

...
validator.webServiceId = PurchaseOrderValidator
validator.webServiceDescription.contentToValidate = The purchase order content to validate
validator.webServiceDescription.contentSyntax = The syntax (mime type) of the purchase order
validator.webServiceDescription.validationType = The type of validation to perform ('basic' or 'large')
validator.webServiceDescription.externalRules = Skip this as externally provided SHACL shapes are not supported

Will produce a response as follows:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns4:GetModuleDefinitionResponse xmlns:ns2="http://www.gitb.com/core/v1/" xmlns:ns3="http://www.gitb.com/tr/v1/" xmlns:ns4="http://www.gitb.com/vs/v1/">
         <module operation="V" id="PurchaseOrderValidator">
            <ns2:metadata>
               <ns2:name>PurchaseOrderValidator</ns2:name>
               <ns2:version>1.0.0</ns2:version>
            </ns2:metadata>
            <ns2:inputs>
               <ns2:param type="binary" name="contentToValidate" use="R" kind="SIMPLE" desc="The purchase order content to validate"/>
               <ns2:param type="string" name="embeddingMethod" use="O" kind="SIMPLE" desc="The embedding method to consider for the 'contentToValidate' input ('BASE64', 'URL' or 'STRING')."/>
               <ns2:param type="string" name="contentSyntax" use="O" kind="SIMPLE" desc="The syntax (mime type) of the purchase order"/>
               <ns2:param type="string" name="validationType" use="O" kind="SIMPLE" desc="The type of validation to perform ('basic' or 'large')"/>
               <ns2:param type="list[map]" name="externalRules" use="O" kind="SIMPLE" desc="Skip this as externally provided SHACL shapes are not supported"/>
            </ns2:inputs>
         </module>
      </ns4:GetModuleDefinitionResponse>
   </soap:Body>
</soap:Envelope>

Running the validation itself is done through the validate operation. This expects the following inputs:

Input Description Required? Type Default value
contentToValidate The content to validate. Yes A string that is interpreted based on the embeddingmethod input.  
embeddingMethod The way in which to interpret the contentToValidate value. Yes, but should be skipped in favour of the embeddingMethod attribute - see below. One of BASE64 (for content embedded as a BASE64 encoded string), URL (for a reference to remote content) or STRING (for content embedded as-is).  
contentSyntax The syntax of the provided content. Yes, unless the content is provided as a URI for a file with a well-known extension. A mime type string (e.g. text/turtle).  
validationType The type of validation to perform. Yes, unless a single validation type is defined. String The single configured validation type (if defined).
reportSyntax The syntax (provided as a mime type) for the resulting report (can be skipped for the default syntax). No A mime type string (e.g. text/turtle). The default configured for the validator (application/rdf+xml if not overriden).
externalRules A list of user-provided SHACL shape extensions to be considered with any predefined ones. These are accepted only if explicitly allowed in the configuration for the validation type in question. A list of map entries (see below for content). No  

Regarding the externalRules, this is a list of one of more entries. For each such entry the following input properties are expected:

Input Description Required? Type
ruleSet The RDF content with the SHACL shape extensions. Yes A string that is interpreted based on the embeddingMethod input.
embeddingMethod The way in which to interpret the ruleSet input value. Yes, but should be skipped in favour of the embeddingMethod attribute - see below. One of BASE64 (for content embedded as a BASE64 encoded string), URL (for a reference to remote content) or STRING (for content embedded as-is).
ruleSyntax The syntax to consider for the provided RDF content. Yes, unless the content is provided as a URI for a file with a well-known extension. A mime type string (e.g. text/turtle).

The GITB SOAP API that the validator realises foresees flexibility in how each provided value is interpreted. This is done via the embeddingMethod attribute that is defined on each input element. The values it supports are:

Value Description
STRING The value is interpreted as-is as an embedded text.
BASE64 The value is interpreted as an embedded BASE64 string that will need to be decoded before processing.
URI The content is interpreted as a remote URI reference that will be looked up before processing.

Note

Setting the embeddingMethod: The embeddingMethod attribute is expected for all inputs, not only the contentToValidate and ruleSet inputs where it would make most sense. In all cases where simple values are needed you should set this to STRING.

The sample SOAP UI project includes sample requests per case. As an example, validating via URI would be done using the following envelope:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.gitb.com/vs/v1/" xmlns:v11="http://www.gitb.com/core/v1/">
   <soapenv:Header/>
   <soapenv:Body>
      <v1:ValidateRequest>
         <sessionId>?</sessionId>
         <input name="contentToValidate" embeddingMethod="URI">
            <v11:value>https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl</v11:value>
         </input>
         <input name="validationType" embeddingMethod="STRING">
            <v11:value>large</v11:value>
         </input>
      </v1:ValidateRequest>
   </soapenv:Body>
</soapenv:Envelope>

A more complex case would be where user-provided SHACL shape extensions are provided (if allowed by the configuration). The following example submits content for validation via URI and provides two SHACL extension files, both provided as remote URI references:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:v1="http://www.gitb.com/vs/v1/" xmlns:v11="http://www.gitb.com/core/v1/">
<soapenv:Header/>
<soapenv:Body>
    <v1:ValidateRequest>
        <sessionId>123</sessionId>
        <input name="contentToValidate" embeddingMethod="URI">
            <v11:value>https://www.itb.ec.europa.eu/files/samples/shacl/sample-invalid.ttl</v11:value>
        </input>
        <input name="validationType" embeddingMethod="STRING">
            <v11:value>large</v11:value>
        </input>
        <input name="externalRules">
            <v11:item>
                <v11:item name="ruleSet" embeddingMethod="URI">
                    <v11:value>https://path.to.rules/shape_extensions_1.ttl</v11:value>
                </v11:item>
            </v11:item>
            <v11:item>
                <v11:item name="ruleSet" embeddingMethod="URI">
                    <v11:value>https://path.to.rules/shape_extensions_2.ttl</v11:value>
                </v11:item>
            </v11:item>
        </input>
    </v1:ValidateRequest>
</soapenv:Body>
</soapenv:Envelope>

The resulting report in all cases is XML-based and uses the GITB TRL syntax:

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <ns4:ValidationResponse xmlns:ns2="http://www.gitb.com/core/v1/" xmlns:ns3="http://www.gitb.com/tr/v1/" xmlns:ns4="http://www.gitb.com/vs/v1/">
         <report name="SHACL Validation">
            <ns3:date>2019-06-24T15:42:45.959Z</ns3:date>
            <ns3:result>FAILURE</ns3:result>
            <ns3:counters>
               <ns3:nrOfAssertions>0</ns3:nrOfAssertions>
               <ns3:nrOfErrors>1</ns3:nrOfErrors>
               <ns3:nrOfWarnings>0</ns3:nrOfWarnings>
            </ns3:counters>
            <ns3:context type="map">
               <ns2:item name="input" embeddingMethod="STRING" type="string">
                  <ns2:value><![CDATA[@prefix ns0: <http://www.w3.org/ns/locn#> .
@prefix ns1: <http://itb.ec.europa.eu/sample/po#> .

<http://my.sample.po/po#home>
  a <http://www.w3.org/ns/locn#Address> ;
  ns0:fullAddress "Rue du Test 123, 1000 - Brussels, Belgium" ;
  ns0:thoroughfare "Rue du Test" ;
  ns0:locatorDesignator "123" ;
  ns0:postCode "1000" ;
  ns0:postName "Brussels" ;
  ns0:adminUnitL1 "BE" .

<http://my.sample.po/po#purchaseOrder>
  a <http://itb.ec.europa.eu/sample/po#PurchaseOrder> ;
  ns1:shipTo <http://my.sample.po/po#home> ;
  ns1:hasItem <http://my.sample.po/po#item1> ;
  ns1:hasItem <http://my.sample.po/po#item2> .

<http://my.sample.po/po#item1>
  a ns1:Item ;
  ns1:productName "Mouse" ;
  ns1:quantity 20 ;
  ns1:priceEUR 15.99 .

<http://my.sample.po/po#item2>
  a ns1:Item ;
  ns1:productName "Keyboard" ;
  ns1:quantity 3 ;
  ns1:priceEUR 25.50 .]]></ns2:value>
               </ns2:item>
               <ns2:item name="shapes" embeddingMethod="STRING" type="string">
                  <ns2:value><![CDATA[<rdf:RDF
    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
    xmlns:po="http://itb.ec.europa.eu/sample/po#"
    xmlns:locn="http://www.w3.org/ns/locn#"
    xmlns:sh="http://www.w3.org/ns/shacl#"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema#">
  <sh:NodeShape rdf:about="http://itb.ec.europa.eu/sample/po#LargeItemShape">
    <sh:targetClass rdf:resource="http://itb.ec.europa.eu/sample/po#Item"/>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#minimumItemsForLargeOrderShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#quantity"/>
        <sh:minExclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >10</sh:minExclusive>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
  </sh:NodeShape>
  <sh:NodeShape rdf:about="http://itb.ec.europa.eu/sample/po#ItemShape">
    <sh:targetClass rdf:resource="http://itb.ec.europa.eu/sample/po#Item"/>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#productNameShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#productName"/>
        <sh:minCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:minCount>
        <sh:maxCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:maxCount>
        <sh:nodeKind rdf:resource="http://www.w3.org/ns/shacl#Literal"/>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#quantityShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#quantity"/>
        <sh:minCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:minCount>
        <sh:maxCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:maxCount>
        <sh:datatype rdf:resource="http://www.w3.org/2001/XMLSchema#integer"/>
        <sh:minExclusive rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >0</sh:minExclusive>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#priceShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#priceEUR"/>
        <sh:minCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:minCount>
        <sh:maxCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:maxCount>
        <sh:datatype rdf:resource="http://www.w3.org/2001/XMLSchema#decimal"/>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
  </sh:NodeShape>
  <sh:NodeShape rdf:about="http://itb.ec.europa.eu/sample/po#PurchaseOrderShape">
    <sh:targetClass rdf:resource="http://itb.ec.europa.eu/sample/po#PurchaseOrder"/>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#shipToShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#shipTo"/>
        <sh:minCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:minCount>
        <sh:maxCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:maxCount>
        <sh:class rdf:resource="http://www.w3.org/ns/locn#Address"/>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#billToShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#billTo"/>
        <sh:class rdf:resource="http://www.w3.org/ns/locn#Address"/>
        <sh:maxCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:maxCount>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
    <sh:property>
      <sh:PropertyShape rdf:about="http://itb.ec.europa.eu/sample/po#hasItemsShape">
        <sh:path rdf:resource="http://itb.ec.europa.eu/sample/po#hasItem"/>
        <sh:minCount rdf:datatype="http://www.w3.org/2001/XMLSchema#integer"
        >1</sh:minCount>
        <sh:class rdf:resource="http://itb.ec.europa.eu/sample/po#Item"/>
        <sh:severity rdf:resource="http://www.w3.org/ns/shacl#Violation"/>
      </sh:PropertyShape>
    </sh:property>
  </sh:NodeShape>
</rdf:RDF>]]></ns2:value>
               </ns2:item>
            </ns3:context>
            <ns3:reports>
               <ns3:error xsi:type="ns3:BAR" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                  <ns3:description>Value is not > 10^^http://www.w3.org/2001/XMLSchema#integer</ns3:description>
                  <ns3:location>Focus node [http://my.sample.po/po#item2] - Result path [http://itb.ec.europa.eu/sample/po#quantity]</ns3:location>
                  <ns3:test>Shape [http://itb.ec.europa.eu/sample/po#minimumItemsForLargeOrderShape] - Value [3]</ns3:test>
               </ns3:error>
            </ns3:reports>
         </report>
      </ns4:ValidationResponse>
   </soap:Body>
</soap:Envelope>

The report includes:

  • The validation timestamp (in UTC).
  • The overall result (SUCCESS or FAILURE).
  • The count of errors, warnings and information messages.
  • The context for the validation (i.e. the content that was validated and the applied SHACL shapes).
  • The list of report items displaying per item its description, location in the validated content (using the focus node and path) and performed test (using the applied shape’s name and the tested value).

Step 7: Use the validator in GITB TDL test cases

As a next step over the standalone validator you may consider using it from within GITB TDL test cases running in the test bed. You would typically do this for the following reasons:

  • You want to control access to the validation service based on user accounts.
  • You prefer to record all data linked to validations (for e.g. subsequent inspection).
  • You want to build complete conformance testing scenarios that are either focused on the validator or that use it as part of validation steps.

As described in Validation via SOAP web service API, the standalone validator offers by default a SOAP API for machine-to-machine integration that realises the GITB validation service specification. In short this means that the service can be easily included in any GITB TDL test case as the handler of a verify step by supplying as its value the full URL to the service’s WSDL.

The following example is a test case that validates purchase orders as being large. The input content is requested as a file from the user as well as the syntax to consider (based on a predefined set of options):

<?xml version="1.0" encoding="UTF-8"?>
<testcase id="testCase1_upload" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    <metadata>
        <gitb:name>testCase1_upload</gitb:name>
        <gitb:version>1.0</gitb:version>
        <gitb:description>Test case that allows the developer of an EU retailer system to upload a purchase order for validation as being considered large.</gitb:description>
    </metadata>
    <actors>
        <gitb:actor id="Retailer" name="Retailer" role="SUT"/>
    </actors>
    <steps>
        <!--
            Request from the user the content to validate as a file and its syntax.
        -->
        <interact id="userData" desc="Upload content">
            <request name="content" desc="Purchase order to validate:" contentType="BASE64"/>
            <request name="syntax" desc="Content syntax:" options="application/json+ld, application/rdf+xml, text/turtle" optionLabels="JSON-LD, RDF/XML, Turtle"/>
        </interact>
        <!--
            Trigger the validation.
        -->
        <verify handler="https://www.itb.ec.europa.eu/shacl/soap/order/validation?wsdl" desc="Validate purchase order">
            <input name="contentToValidate">$userData{content}</input>
            <input name="contentSyntax">$userData{syntax}</input>
            <input name="validationType">"large"</input>
        </verify>
    </steps>
</testcase>

Note that the input names (contentToValidate, contentSyntax and validationType) correspond to those expected by the SOAP API (see Validation via SOAP web service API). For string or binary content you typically don’t need to provide the embeddingMethod as this is determined automatically by the test bed. If however you are using string variables that contain BASE64 or URI references you would need to define this explicitly.

An example of this is a test case that requests the content from the user as a URI:

<testcase id="testCase1_upload" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    ...
    <steps>
        <!--
            Request from the user the content to validate as a URI.
            The syntax will be determined from the file's extension.
        -->
        <interact id="userData" desc="Provide input">
            <request name="content" desc="URI of the purchase order to validate:"/>
        </interact>
        <!--
            Trigger the validation.
        -->
        <verify handler="https://www.itb.ec.europa.eu/shacl/soap/order/validation?wsdl" desc="Validate purchase order">
            <input name="contentToValidate">$userData{content}</input>
            <!--
                Explicitly define the embeddingMethod to consider.
            -->
            <input name="embeddingMethod">"URL"</input>
            <input name="validationType">"large"</input>
        </verify>
    </steps>
</testcase>

A more complicated example is when external SHACL shapes are to be provided (if supported for the validation type in question). The following example shows two such extensions being provided, one as a URI and one from a file included in the test suite itself:

<?xml version="1.0" encoding="UTF-8"?>
<testcase id="testCase1_upload" xmlns="http://www.gitb.com/tdl/v1/" xmlns:gitb="http://www.gitb.com/core/v1/">
    ...
    <imports>
        <!--
            Import the additional shapes to consider from the test suite.
        -->
        <artifact type="binary" name="additionalShapes">resources/additional-shapes.ttl</artifact>
    </imports>
    <variables>
        <!--
            Define variables for the SHACL shape extensions.
        -->
        <var name="externalRules" type="list[map]"/>
        <!--
            First set of rules defined through a URL reference.
            The "ruleSyntax" is not needed as it can be determined from the referenced file.
        -->
        <var name="ruleSet1" type="map">
            <value name="ruleSet" type="string">https://path.to.rules/shape_extensions.ttl</value>
            <value name="embeddingMethod" type="string">URL</value>
        </var>
        <!--
            Second set of rules defined as BASE64 (to be assigned once the test starts).
            The "embeddingMethod" will be automatically set given that a file will be used.
        -->
        <var name="ruleSet2" type="map">
            <value name="ruleSyntax" type="string">text/turtle</value>
        </var>
    </variables>
    ...
    <steps>
        <!--
            Add as the "ruleSet" value the imported shapes from the test suite.
            This will also automatically set the "embeddingMethod" to "BASE64".
        -->
        <assign to="$ruleSet2{ruleSet}" type="binary">$additionalShapes</assign>
        <!--
            Add both additional sets of rules to the input list.
        -->
        <assign to="$externalRules" append="true">$ruleSet1</assign>
        <assign to="$externalRules" append="true">$ruleSet2</assign>
        <interact id="userData" desc="Upload content">
            <request name="content" desc="Purchase order to validate:" contentType="BASE64"/>
            <request name="syntax" desc="Content syntax:" options="application/json+ld, application/rdf+xml, text/turtle" optionLabels="JSON-LD, RDF/XML, Turtle"/>
        </interact>
        <verify handler="https://www.itb.ec.europa.eu/shacl/soap/order/validation?wsdl" desc="Validate purchase order">
            <input name="contentToValidate">$userData{content}</input>
            <input name="contentSyntax">$userData{syntax}</input>
            <input name="validationType">"large"</input>
            <!--
                Pass the list of additional shapes to consider.
            -->
            <input name="externalRules">$externalRules</input>
        </verify>
    </steps>
</testcase>

One additional point to make is on the definition of the service’s WSDL (i.e. the handler value). Although you can define this directly as in the previous examples, a better approach to improve portability is to define this in the test bed’s domain configuration as a domain parameter. Defining a validationService parameter in the domain you could thus redefine the verify step as:

...
<verify handler="$DOMAIN{validationService}" desc="Validate purchase order">
    ...
</verify>
...

Summary

Congratulations! You have just setup a validation service for your RDF specification. In doing so you considered your needs and defined your service through configuration on the ISA² test bed or as a Docker container. In addition, you used this service via its different APIs and considered how this could be used as part of complete conformance testing scenarios.

See also

In Step 7: Use the validator in GITB TDL test cases we briefly touched upon using the test bed for complete conformance testing scenarios. If this interests you, several additional guides are available that can provide you with further information:

For the full information on GITB TDL test cases check out the GITB TDL documentation, the reference for all test step constructs as well as a source of numerous complete examples.

In case you need to consider also validation of XML-based specifications, the test bed provides similar support to easily configure and use an XML validator. For more information on this check Guide: Setting up XML validation.

Finally, for more information on Docker and the commands used in this guide, check out the Docker online documentation.

References

This section contains additional references linked to this guide.

Validator configuration properties

The following sections list the configuration properties you can use to customise the operation of your validation service.

Domain-level configuration

The properties in this section are to be provided in the configuration property file (one per configured validation domain) you define as part of your validator configuration.

Property Description Type Default value
validator.channels Comma-separated list of validation channels to have enabled. Possible values are (form, rest_api, soap_api). Comma-separated Strings form, rest_api, soap_api
validator.type Comma-separated list of supported validation types. Values need to be reflected in properties validator.typeLabel, validator.shaclFile, validator.externalShapes. Comma-separated Strings  
validator.typeLabel.XYZ Label to display in the web form and REST API (info operation) for a given validation type (added as a postfix of validator.typeLabel). Only displayed if there are multiple types. String  
validator.webServiceId The ID of the SOAP web service. String ValidatorService
validator.webServiceDescription.contentToValidate The description of the SOAP web service for element “contentToValidate”. String The content to validate, provided as a string, BASE64 or a URI.
validator.webServiceDescription.contentSyntax The description of the SOAP web service for element “contentSyntax”. String The mime type of the provided content.
validator.webServiceDescription.validationType The description of the SOAP web service for element “validationType”. Only displayed if there are multiple types. String The type of validation to perform (if multiple types are supported).
validator.webServiceDescription.externalRules The description of the SOAP web service for element “externalRules”. String A list of maps that defines external SHACL shapes to consider in addition to any preconfigured ones. Each map item corresponds to a SHACL file and defines the following keys: 'ruleSet' (the rules to consider, see 'contentToValidate' for its semantics), 'ruleSyntax' (the syntax of the 'ruleSet' content, see 'contentSyntax' for its semantics), 'embeddingMethod' (the way to consider the 'ruleSet' value).
validator.webServiceDescription.embeddingMethod The description of the SOAP web service for element “embeddingMethod”. String The embedding method to consider for the 'contentToValidate' input ('BASE64', 'URL' or 'STRING').
validator.shaclFile.XYZ Comma-separated list of SHACL shape files loaded for a given validation type (added as a postfix). These can be a files or folders. Comma-separated Strings  
validator.shaclFile.XYZ.remote.N.url Reference for a remotely loaded SHACL shape file for a given validation type (added as the XYZ placeholder). One or more such entries can be defined by incrementing the zero-based N counter. String  
validator.shaclFile.XYZ.remote.N.type The content type for the remotely loaded SHACL shape file defined in the corresponding validator.shaclFile.XYZ.remote.N.url property. This can be skipped if the type can be determined from the referenced file name. String (as mime type)  
validator.externalShapes.XYZ Whether or not user-provided shapes are allowed for the given validation type (added as a postfix). Boolean false
validator.defaultReportSyntax The default report syntax to be returned if none is explicitly requested. String (as mime type) application/rdf+xml
validator.contentSyntax The RDF content syntaxes (as mime types) that the web user interface will support for input and output. Comma-separated Strings application/ld+json, application/rdf+xml, text/turtle, application/n-triples
validator.reportsOrdered Whether the report items are to be ordered (errors first, then warnings, then messages). Otherwise the items will appear based on where they were raised in the validated content. Boolean false
validator.showAbout Whether or not to show the about panel on the web UI. Boolean true

Application-level configuration

These properties govern the validator’s application instance itself. They apply only when you are defining your own validator as a Docker image in which case they are supplied as environment variables (ENV directives in a Dockerfile). Note that apart from these properties any Spring Boot configuration property can also be supplied.

Note

Mandatory property: The only mandatory property that needs to be defined is validator.resourceRoot.

Property Description Type Default value
validator.resourceRoot The root folder under which domain subfolders will be loaded from. String  
validator.domain The names of the domain subfolders to consider. By default all folders under validator.resourceRoot will be considered. Comma-separated Strings  
validator.domainName.XYZ The name to display for a given domain folder. This value will also be used in request paths. String The folder name is used.
logging.path Path to a folder that will hold the validator’s log output. String /validator/logs
validator.tmpFolder Path to a folder that contains temporary data and reports. String /validator/tmp
validator.acceptedShaclExtensions Accepted local SHACL file extensions. All other files found in validator.shaclFile.XYZ (when folders are defined) are ignored. Comma-separated Strings rdf, ttl, jsonld
validator.acceptedHeaderAcceptTypes Accepted Accept header syntaxes for the report type (used in the REST API). Comma-separated Strings application/rdf+xml, application/ld+json, text/turtle, , application/n-triples
validator.defaultReportSyntax Global default report syntax, applied if not overriden at domain level or by the user’s request. String (as mime type) application/rdf+xml
validator.contentSyntax Global default supported content syntaxes for the web upload form if not overriden at domain level. Comma-separated Strings application/ld+json, application/rdf+xml, text/turtle, application/n-triples
validator.cleanupRate The rate at which the external file cache is refreshed (in milliseconds). Long 3600000
validator.cleanupWebRate The rate at which temporary files linked to the web form are cleaned (in milliseconds). Long 600000
validator.docs.licence.description Description of the licence in the Swagger UI. String, European Union Public Licence (EUPL) 1.2
validator.docs.licence.url URL to the licence for the Swagger UI. String, https://eupl.eu/1.2/en/
validator.docs.version Version number to display in the Swagger UI. String, 1.0.0
validator.docs.title Title to display in the Swagger UI. String, SHACL Validator REST API
validator.docs.host The host to display as the root for the REST API Swagger documentation. String localhost:8080
validator.docs.schemes Comma-separated scheme values for the Swagger documentation Comma-separated Strings http
validator.hydraServer The server part to add as of the REST API’s vocabulary’s URL for the Hydra documentation. String http://localhost:${server.port}
validator.hydraRootPath The root path to append to the validator.hydraServer for the Hydra documentation of the REST API. String ${server.servlet.context-path}