Introduction
This second part begins with implementing a software component that creates the schema and, therefore, the interface. We will describe the toolset for implementing that component and then focus on a primary ontology concept: namespaces. How to translate them in the GraphQL world?
At the end of the implementation, it must be possible to
- access a GraphQL endpoint
- use the Introspection API
- browse the schema discussed here.
Development Environment
Here is our toolset:
The sample code we will discuss in this article is hosted in a private GitHub repository. If you want to have a look, just send us an email, and we will be happy to give you access.
Let’s begin!
The App
As said, the app providing the GraphQL service is a Spring Boot App. Nothing in particular to add: the ontologies we want to use for initializing the module are defined in the configuration. In the following example, we are using the Dublin Core and Friend Of A Friend (FOAF) ontologies
spring:
application:
name: graphowl-engine-api
graphiql:
enabled: true
graphowl:
ontologies: https://protege.stanford.edu/plugins/owl/dc/dublincore.owl,https://web.archive.org/web/20220614105937if_/http://xmlns.com/foaf/spec/20140114.rdf
Note we use the GraphIQL UI for experimenting. We also use Spring profiles for defining several use cases, each one experimenting with one or more ontologies. Here’s a screenshot of the resources folder:

The folder includes several examples:
- the default application.yml uses FOAF + DC
- application-bibframe.yml uses BIBFRAME
- application-foaf.yml: uses FOAF
- application-musicontology.yml uses the Music Ontology
Namespaces As Top Level (Query) Types
The input of the system we are dealing with is an arbitrary ontology or even a set of ontologies.
The first types we want to define in the schema are the namespaces: for each, there should be a corresponding field under the top-level GraphQL Query type.
Namespaces are usually declared at the very beginning of XML documents. Ontologies don’t differ: if, for example, we use BIBFRAME as input ontology, here’s the list of the namespaces used:
...
For each namespace, we should create a type which includes just two properties (for the moment):
- “uri”: which maps to the namespace URI
- “prefix”: the short mnemonic code associated with the namespace URI
When the app load using the default profile (which uses FOAF and DC) here’s what we get from the GraphQL Introspection API (GraphiQL uses those API in the right column)


At first sight, it could sound confusing: field names and types share the same name. Yes, that’s correct, and I agree that it could be a bit misleading; however, this is mainly due to the lack of the namespace “concept” in the GraphQL world.
Apart from the schema, the idea is simple if we consider the “query requestor” perspective. When someone wants to execute a query, it must declare the namespace that owns the entity/entities that compose the response.
Remember, this is just the first brick of our system, so again, being partial, the interaction and the interface are not yet clear. Let’s say, at this point, we can query a namespace like this:
query {
foaf {
uri
prefix
}
}
And get the following response:
{
"data": {
"foaf": {
"uri": "http://xmlns.com/foaf/0.1/",
"prefix": "foaf"
}
}
}
The Implementation
How do we extract the namespaces from the input set of ontologies? As said, namespaces are usually put at the very beginning of an XML document. However, they can also be defined within the document itself, for qualifying specific elements or attributes). As a consequence of that, we should traverse the document(s), collect each distinct namespace and create a corresponding Query field in the GraphQL schema.
While parsing the document, we collect, for each namespace, the prefix and the URI. In that way, other than creating the schema structures, we can also implement the corresponding data fetchers. Here’s the code
private void registerOntologyNamespaces(
RuntimeWiring.Builder registryBuilder,
TypeDefinitionRegistry registry,
String ontologyUrl) {
// Read the ontology from its URL
var url = new URL(ontologyUrl);
var connection = url.openConnection();
try (var stream = connection.getInputStream()) {
// Create the DOM representation of the ontology XML document
var factory = DocumentBuilderFactory.newInstance();
var builder = factory.newDocumentBuilder();
var ontologyDocument = builder.parse(stream);
// Retrieve the top-level GraphQL Query type
var queryTypeDefinition = registry.getType(C_Query).orElseThrow();
var queryNamedChildren = queryTypeDefinition.getNamedChildren();
var topLevelQueries = queryNamedChildren.getChildren(C_fieldDefinitions);
// Retrieve the GraphQL String type (for literals)
var stringDataType = TypeName.newTypeName("String").build();
// Iterate over all elements
var xPath = XPathFactory.newInstance().newXPath();
var allNodes = xPath.compile("//*");
var nodes = (NodeList) allNodes.evaluate(ontologyDocument, XPathConstants.NODESET);
for (int i = 0; i < nodes.getLength(); i++) {
var node = nodes.item(i);
if (node.hasAttributes()) {
// for each element, get its attributes
var attributes = node.getAttributes();
for (int y = 0; y < attributes.getLength(); y++) {
var attribute = attributes.item(y);
var attributeName = attribute.getNodeName();
// is it a namespace declaration?
if (attributeName.startsWith(XMLNS_PREFIX)) {
var prefix = attributeName.substring(XMLNS_PREFIX.length());
var namespaceURI = attribute.getNodeValue();
// Did we already register the namespace?
if (registry.hasType(TypeName.newTypeName(prefix).build())) {
continue;
}
var typeDef = new ObjectTypeDefinition(prefix);
var namespaceNamedChildren = typeDef.getNamedChildren();
var namespaceFields = namespaceNamedChildren.getChildren(C_fieldDefinitions);
// "uri" field for the namespace
namespaceFields.add(newFieldDefinition().name("uri")
.comments(List.of(new Comment("The Uniform Resource Identifier (URI) associated with this namespace.", null)))
.type(stringDataType)
.build());
// "prefix" field for the namespace
namespaceFields.add(newFieldDefinition().name("prefix")
.comments(List.of(new Comment("A short mnemonic code associated with this namespace URI.", null)))
.type(stringDataType)
.build());
topLevelQueries.add(newFieldDefinition()
.name(prefix)
.type(TypeName.newTypeName(prefix).build())
.build());
registry.add(typeDef.withNewChildren(namespaceNamedChildren));
// Data fetcher for "uri" and "prefix" fields
registryBuilder.type(newTypeWiring(C_Query)
.dataFetcher(prefix, context ->
Map.of("prefix", prefix,
"uri", namespaceURI)));
}
}
}
}
registry.remove(queryTypeDefinition);
registry.add((SDLDefinition) queryTypeDefinition.withNewChildren(queryNamedChildren));
} catch (Exception exception) {
... log the error
}
}
And here it is. Now,
- start the application
- open your browser
- point to http://127.0.0.1:8080/graphiql
- run the following query
query {
foaf {
uri
prefix
}
}
and expect the following response. You can also try with the other namespaces.

We would love to hear questions, doubts, and feedback about this blog post!
Feel free to contact us or leave a message in the comment box below.