Skip to main content

Custom resource loaders

AMF allows you to define custom resource loaders that you can fully customize and plug into AMF’s parsers.

By default, AMF provides the following resource loaders:

  • JVM
    • FileResourceLoader
    • HttpResourceLoader
  • JS Server
    • JsServerFileResourceLoader
    • JsServerHttpResourceLoader
  • JS Browser
    • JsBrowserHttpResourceLoader

However, you may encounter situations in which you need to parse resources that can't be fetched by a HTTP or file resource loader. Or you may have cases where you want to use a custom nomenclature or resolution mechanism for the URIs used to reference content.

In such cases, use custom resource loaders.

Implement a new resource loader#

To implement a new resource loader, extend the amf.client.resource.ResourceLoader interface and define your own resource loader.

The ResourceLoader interface contains two methods, fetch and accepts:

/** Fetch specified resource and return associated content. Resource should have been previously accepted. */
/** If the resource not exists, you should return a future failed with an ResourceNotFound exception. */
def fetch(resource: String): ClientFuture[Content]
/** Accepts specified resource. */
def accepts(resource: String): Boolean = true
  • accepts(resource: string): boolean

    • AMF uses this method to ask every resource loader in the environment if it can fetch the current resource. If a loader can't fetch the resource, AMF raises an UnsupportedUrlScheme exception.
  • fetch(resource: string): ClientFuture[Content]

    • This method loads the resource according to your custom implementation, and returns an asynchronous Content object.

AMF stores the Content object at amf.client.remote.Content, and it contains:

  • The resource fetched as a stream
  • The URL from which the resource was fetched
  • The media type of the resource

Configure your custom resource loader#

All parsers receive an optional Environment parameter in their constructor. You can use the Environment parameter to add your custom resource loaders:
Environment env = DefaultEnvironment.apply().add(new CustomResourceLoader());
Raml10Parser parser = new Raml10Parser(env);

How URI normalization works#

Before fetching, every URI goes through a normalization process to ensure consistency and standardization. Normalization includes the following steps:

  1. Encode string: Computes a new version of the string in which each instance of certain characters is replaced by one, two, three, or four escape sequences representing UTF-8 character encoding.

  2. Normalization ( Transforms a URI into a normalized, or canonical, URI to determine if two syntactically different URIs are equivalent.

  3. Resolve relativeness: If a URI is relative, appends the location of the file from which the URI originates to the base of the processed relative URI.

Example URI normalization#

The following example demonstrates the normalization process using a RAML API that references an external JSON file:

  • URI of main RAML API: file:///Users/user/api.raml
  • Reference to JSON file: type: !include ./folder/../external file.json

The URI is normalized following the three steps described above:

  • Encode string
    • The URI is transformed to ./folder/../external%20file.json. The blank space between words is encoded.
  • Normalization
    • The relative path and folder structure are removed, the URI is transformed to external%20file.json.
  • Resolve relativeness
    • The reference was relative, so the URI of the main file is appended to the base of the reference URI: file:///Users/user/external%20file.json

Finally, resource loaders will use the following normalized URI to fetch the JSON file: file:///Users/user/external%20file.json.

Example code for a custom resource loader#

The following example code is for a custom resource loader that obtains resources using a custom protocol:

Code extracted from the examples GitHub repository.

Last updated on by arielmirra