Skip to content

Appbase configuration

Dave Reynolds edited this page Sep 2, 2016 · 5 revisions

A sapi application normally uses the appbase machinery for configuration. The web.xml sets up the core machinery and specifies how the appbase configuration is found.

Web.xml

A default web.xml configuration is shown below.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

  <display-name>Data API</display-name>

  <listener>
    <listener-class>com.epimorphics.appbase.core.AppConfig</listener-class>
  </listener>

  <filter>
    <filter-name>CORS</filter-name>
    <filter-class>com.epimorphics.appbase.webapi.CorsFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>CORS</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <filter>
    <filter-name>extension-filter</filter-name>
    <filter-class>com.epimorphics.appbase.webapi.ExtensionFilter</filter-class>
    <init-param>
      <param-name>html</param-name>
      <param-value>text/html</param-value>
    </init-param>
    <init-param>
      <param-name>ttl</param-name>
      <param-value>text/turtle</param-value>
    </init-param>
    <init-param>
      <param-name>rdf</param-name>
      <param-value>application/rdf+xml</param-value>
    </init-param>
    <init-param>
      <param-name>jsonld</param-name>
      <param-value>application/ld+json</param-value>
    </init-param>
    <init-param>
      <param-name>json</param-name>
      <param-value>application/json</param-value>
    </init-param>
    <init-param>
      <param-name>csv</param-name>
      <param-value>text/csv</param-value>
    </init-param>
  </filter>
  
  <filter-mapping>
    <filter-name>extension-filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  <filter>
    <filter-name>VelocityFilter</filter-name>
    <filter-class>com.epimorphics.appbase.webapi.VelocityFilter</filter-class>
  </filter>
  
  <filter>
    <filter-name>LogRequestFilter</filter-name>
    <filter-class>com.epimorphics.simpleAPI.webapi.LogRequestFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>LogRequestFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <filter-mapping>
    <filter-name>VelocityFilter</filter-name>
    <url-pattern>/ui/*</url-pattern>
  </filter-mapping>

  <filter>
    <filter-name>Jersey Web Application</filter-name>
    <filter-class>org.glassfish.jersey.servlet.ServletContainer</filter-class>
    <init-param>
      <param-name>jersey.config.server.provider.packages</param-name>
      <param-value>com.epimorphics.webapi,com.epimorphics.server.webapi,com.epimorphics.simpleAPI.webapi,com.epimorphics.EArealtime.webapi</param-value>
    </init-param>
    <init-param>
      <param-name>jersey.config.servlet.filter.forwardOn404</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  
  <filter-mapping>
    <filter-name>Jersey Web Application</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
 
  <welcome-file-list>
    <welcome-file>ui/index.html</welcome-file>
  </welcome-file-list>
  
  <context-param>
    <param-name>AppConfig.app</param-name>
    <!-- Will initialize from first of these it finds -->
    <param-value>/etc/api/app.conf,/opt/api/conf/app.conf,{webapp}/WEB-INF/app.conf</param-value>
  </context-param>  

</web-app>

The filters for request logging, extension typing, CORS and velocity are all optional but generally useful to have.

The AppConfig.app param gives a search path for locating the appbase configuration file. It's generally useful to have some external locations first then a fall back on something internal to the war. That way you can package a war that's usable out of the box but which can be configured externally.

Example app.conf

For the app.conf file itself then a typical set up is:

# Plugin extension for velocity library, optional
apix                 = com.epimorphics.simpleAPI.webapi.LibAPI

# Velocity engine
velocity             = com.epimorphics.appbase.templates.VelocityRender
velocity.templates   = {webapp}/WEB-INF/templates
velocity.root        = /ui
velocity.production  = true

# Default prefixes
prefixes = com.epimorphics.appbase.core.PrefixService
prefixes.prefixFile    = {webapp}/WEB-INF/prefixes.ttl

# Data source low level
ssource              = com.epimorphics.appbase.data.impl.RemoteSparqlSource
ssource.endpoint     = http://localhost:3030/ds/query

# Wrap low level source in sapi adapater
dsource              = com.epimorphics.simpleAPI.query.impl.SparqlDataSource
dsource.source       = $ssource

# API configuration
api                  = com.epimorphics.simpleAPI.core.API
api.source           = $dsource
api.baseURI          = http://environment.data.gov.uk/flood-monitoring/
api.documentation    = http://environment.data.gov.uk/flood-monitoring/doc/reference
api.publisher        = Environment Agency
api.licence          = http://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/
api.contextURL       = http://environment.data.gov.uk/flood-monitoring/meta/context.jsonld
api.comment          = Status: Beta service
api.endpointSpecDir  = {webapp}/WEB-INF/endpointSpecs
api.maxAge           = 300
api.version          = 0.7

The prefix service allows you to define a default set of prefixes that can be used in endpoint/view specifications without having to locally declare them for each endpoint.

The API object takes a large (and growing) collection of configuration parameters to adapt the API behaviour.

Configuration options

The most critical API configuration settings are:

API parameter Meaning
baseURI The root URI where the API will appear, which may be different from where the webapp is hosted if behind a reverse proxy or if in dev/staging.
source The data source. In principle sources other than SPARQL can be supported but in practice this is normally a SparqlDataSource
endpointSpecDir A directory from which the endpoint and view specifications will be dynamically loaded. Can be in webapp itself (use the {webapp} macro for this)

Each API response has a metadata header which is constructed from the following API settings:

API parameter Meaning
documentation URL for the API documentation
publisher Name or URL for the API publisher
licence URL for set of licence terms
contextURL URL for a JSONLD context file, if available
documentation URL for the API documentation
comment Additional comment text (e.g. describing the status of the API)
version Text string giving the version of the URI

Other configuration options which affect the API processing are:

API parameter Meaning Default
maxAge The maximum age (in seconds) to include in the cache control headers for each response 60
showLangTag If false then lang-tagged literals will be output as plain strings false
showOnlyLang Set to a language code to filter out lang-tagged literals which have a language code other than this one
fullPathsInCSVHeaders If set then CSV headers will show the full dotted property path for the column names true
defaultItemTemplate Name of a velocity template to use for rendering html view of items if there's no endpoint specific one given
defaultListTemplate Name of a velocity template to use for rendering html view of lists if there's no endpoint specific one given
htmlPreferred Set this to force use of html when possible and allowed by content negotation. Useful for clients like IE8 which have strage accept headers. false
htmlNonDefault Set this to true to prefer non-html results (when acceptable to the client) even if the client might prefer HTML. Useful for APIs when customer wants JSON to come up a browser by default but also wants HMTL renders to be available (e.g. through use of .html suffix) false
showSimpleLinks By default resource values will show as json-ld compatible nested objects with an @id field. If this flag is set to true then in the case where the resource has no properties at all then it will render as a simple incline URI string. Mostly a hack to support porting of legacy sapi v.1 applications. false
itemEndpointsReturnArrays If set to true then an item endpoint returns a singleton array of "items", if set to false then the item is returned directly as the value of "items", no array. Default setting (true) is to avoid breaking existing deployments but false makes more sense and useful setting. true

Generic config extensions

It's sometimes useful add additional config settings which are not interpreted by the sapi library itself but are available for use in rendering templates. This is possible through the following structure:

# Additional config
config               = com.epimorphics.appbase.core.GenericConfig
config.lastDate = 2015
config.firstDate = 2005

api.configExtensions = $config

Geo and text search

Some built in support for geo and text search is provided in the form of plug in processors.

# Request processors to support generic geo and start queries
geoProc    = com.epimorphics.simpleAPI.requests.GeoRequestProcessor
searchProc = com.epimorphics.simpleAPI.requests.SearchRequestProcessor
searchProc.filterDistinct = true

api.requestProcessors = $geoProc, $searchProc

[Use api.requestProcessor if there's only one processor to add.]

The search processor looks for query parameter search, transforms that to a conjunctive lucene query and assumes the underlying data source has a jena text index.

The geo processor looks for query parameters lat&long&dist or easting&northing&dist and injects a geospatial query. The query is handled internally using the query transformation service to allow for either direct Sparql or Jena Spatial implementations. To use this you also need to specify which transformation to use and register it as a transformer:

# handle transform setup
# spatial = com.epimorphics.sparql.geo.GeoTransformByJenaSpatial
spatial = com.epimorphics.sparql.geo.GeoTransformBySparqlFilter
apptransforms         = com.epimorphics.simpleAPI.queryTransforms.AppTransforms
apptransforms.include = $spatial

Geo and text search can also be done by injecting special case SPARQL code manually in an sapi-based application.