RDF/OWL content-negotiation using NGINX

Performing content-negotiation for RDF and OWL types with Nginx

A similar particulars for Apache are available from W3C Best practices for publishing RDF Vocabularies

What is content-negotiation?

Wikipedia defines content-negotiation as different (mime types) documents are served at the same URI. In simpler terms, this allows requesting different formats on the same URI. Hence the negotiation of content, as in, the requester asks for a specific content and the server sends it, or replies back with what is available. This allows a single URI for the resource, where the requester can get the data in whatever format they want, provided the server already has that format. So a request for an image at http://example.com/image will image.jpeg if the requester wants a JPEG, or it may send image.png as default.

Content negotiation for RDF and OWL

For serving ontologies and datasets, content negotiation is a valuable mechanism because of the varying formats, while ontologies need to be served with a single, unchanging url. Therefore, say, when an ontology or dataset is served at http://example.com/ontology, the requester can ask for RDF/XML or Turtle or N3, and the server will respond correctly if the file exists on the server. This also puts the onus on the maintainer of the ontology to keep a lot of versions of the ontology to fulfil content negotiation.

Setting up content negotiation on Nginx

Nginx is a simple, versatile web server, which is great for quick handling of web apps, but the content-negotiation aspect is not as fleshed out as with Apache. Therefore, the following will only enable content-negotiation partially and has several holes in it. But it gets the job done.

First, set the following snippet in the http section of /etc/nginx/nginx.conf to map the request type to file types.

map $http_accept $ld_suffix{
    "~*owl" ".owl";
    "~*rdf" ".rdf";
    "~*xml" ".xml";

Then, to make Nginx aware of mime types we want to serve, add the following in /etc/nginx/mime.types to the existing types dictionary.

    text/turtle                           ttl;
    application/rdf+xml                   rdf;
    application/n-triples                 nt;
    application/ld+json                   jsonld;
    application/owl+xml                   owl;
    text/trig                             trig;
    application/n-quads                   nq;

Once this is done, open the webapp configuration (usually in sites-*) and set it up so-

location /ontologies {
    alias /apps/ontologies;
    autoindex on;
    try_files $uri $uri$ld_suffix =404;

which will serve the files out of /apps/ontologies/ by basically trying out different combinations of files, and if not available, will sent a HTTP-404. An easy way to test this is using curl as -

curl -I -L -H "Accept: <MIME-TYPE>"  URI
# response should contain
# Content-Type: <MIME-TYPE>