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.
- 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
-
fetch(resource: string): ClientFuture[Content]
- This method loads the resource according to your custom implementation, and returns an asynchronous
Content
object.
- This method loads the resource according to your custom implementation, and returns an asynchronous
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:
-
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.
-
Normalization (
java.net.URI.normalize
): Transforms a URI into a normalized, or canonical, URI to determine if two syntactically different URIs are equivalent. -
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.
- The URI is transformed to
- Normalization
- The relative path and folder structure are removed, the URI is transformed to
external%20file.json
.
- The relative path and folder structure are removed, the URI is transformed to
- 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
- The reference was relative, so the URI of the main file is appended to the base of the reference URI:
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:
- Java
- JavaScript
Code extracted from the examples GitHub repository.
Code extracted from the examples GitHub repository.