Skip to content
Aaron Phethean edited this page Oct 28, 2013 · 1 revision

Resource Interaction Model (0.3.0)

The Resource Interaction Model (RIM) language allows you to quickly and easily create REST APIs for use by humans and machines.

HelloWorld.rim

rim HelloWorld {
// Define the HTTP methods your intend to use and a nice name if you prefer [alias] [HTTP method]
events
	SEE GET
end

// Define a set of commands available to your resources.
// Generally a small set of commands will be reused for a number of resources.
commands
	GETEntities
	Noop optional_configuration_props
end

// Define a resource that is nothing more than a link to some messages
initial resource root
	item ROOT
	view { Noop }
	path "/"
	SEE -> messages
end

// Define a resource that will show a collection of messages
resource messages
	collection Message
	view { GETEntities }
end
}

Overview

The RIM language uses resources and transitions to define RESTful services; this manner of defining a service is very similar to a state machine or directional graph. Resources are identified by name and all resources must be addressable from at least one other resource. To create a RESTful service, as defined by Roy Fielding, resources must conform to four Uniform Interface constraints: identification of resources; manipulation of resources through representations; self-descriptive messages; and, hypermedia as the engine of application state. The RIM language ensures these constraints can be met at runtime by enforcing the resource naming, transition, metadata, and action semantics.

resource

The RIM language uses the resource nomenclature to define a container for an entity or multiple entities. e.g. the example resource below represents a collection of Message entities.

resource messages
	collection Message
	view { GETHelloMessage }
end

A resource MUST be given a unique name, it MUST provide a view command or workflow, and it MUST represent either an item or a collection of an entity.

To be considered valid, a RIM definition MUST define exactly one initial resource; all other resources MUST have at least one transition from another resource.

view

A command or workflow that will be executed when a safe transition to a state is issued.

resource messages
	collection Message
	view { GETHelloMessage }
end

actions

A list of command or workflow, separated by ;, that will be executed when an unsafe transition to a state is made.

resource messages
	collection Message
	view { GETHelloMessage }
	actions { GETHelloMessage; UpdateMessage }
end

relations

A list of relations that will be used in any links to this state.

resource messages
	collection Message
	view { GETHelloMessage }
	relations { "mylinkrelation" }
end

type

A resource can define one of two types of resource; they are either an item or a collection

item

An individual.

collection

A collection of individuals.

initial resource

An initial resource is a special resource state that identifies a logical entry point to the interaction model. It MAY be used by a runtime container to understand the starting point(s) of the resource graph, a runtime container MAY only bind resources to paths when they exist in the graph from this initial starting point.

initial resource Root
	item ServiceDocument
	view { GETServiceDocument }
end

A set of resource interaction models MUST define one initial resource.

exception resource

An exception resource is a special resource state used to catch interaction errors for resources which do not have an onerror handler.

exception resource AirlineException
	item AirlineError
	view { GETException }
end

Transitions

Defining transitions

Transitions are mostly commonly represented as links through a given media type. They are the main way we provide state or context to our application interactions and they define how a User-Agent can interact with our service.

-> transition

Single transition.

initial resource root
	item ROOT
	actions { Noop }
	path "/"
	GET -> messages
end

resource messages
	collection Message
	view { GETHelloMessage }
end

*-> transition

For each item transition.

--> transition

An auto transition.

Transition linkage

A transition from one resource to another may be loosely defined, dynamic or transient in nature. In such cases it is necessary to define the transition linkage parameters. e.g. the flights resource in the following example uses the flightID field from the Flight entity to transition to the flight resource, where flight requires an id path parameter.

resource flights
	collection Flight
	view { GETEntities }
	path "/Flight"
	GET *-> flight id=flightID
end

resource flight
	item Flight
	view { GETEntity }
	path "/Flight({id})"
end

Transition conditionals

A transition from one resource to another may be conditional on the existence or non-existence of another resource. For example, a successful update may transition to the item whereas an unsuccessful update may remove the resource and require a transition to the collection. In such cases it is possible to define conditional link expressions using the OK() and NOT_FOUND() functions. It is possible to use these transition conditions on all types of transitions.

events
	GET GET
	UPDATE PUT
end
commands
	GetEntities properties
	GetEntity properties
	PutEntity properties
end
initial resource A
	collection ENTITY
	view { GetEntities }
	GET *-> B
end
resource B	item ENTITY
	view { GetEntity }
	UPDATE -> B_pseudo
end
resource B_pseudo	item ENTITY
	actions { PutEntity }
	GET --> A (NOT_FOUND(B))
	GET --> B  (OK(B))
end

events

Define/describe the semantics of a transition to a resource.

Defining an event alias

A runtime container is expected to understand at least the primitive HTTP events GET, PUT, POST, DELETE, HEAD, and OPTIONS. These events can be given an alias to aide understanding in a domain where HTTP is not the normal conversational way of describing an interaction.

events
	SEE GET
	REMOVE DELETE
end

onerror events

The onerror keyword declares an error handler which enables resources to delegate the error handling to other resources.

resource flights
	collection Flight
	view { GETEntities }
	path "/Flight"
	GET *-> flight id=flightID
	onerror --> flightError
end

resource flightError
	item FlightError
	view { GETFlightError }
end

The result of executing the view action on the error resource will be returned as the response of the current request. It may be desirable to return a link to an error details resource in case the current request should return something else such as e.g. a summary of errors.

resource flights
        ...
	onerror --> flightErrorSummary
end

resource flightErrorSummary
	item FlightErrorSummary
	view { GETFlightErrorSummary }
        GET -> flightErrors
end

resource flightErrors
	item FlightError
	view { GETFlightErrors }
end

The additional complexity involved in this step is that a user will have to access flightErrors with a separate request. It is therefore the responsibility of the GETFlightErrorSummary command to store the errors details and GETFlightErrors to retrieve it from intermediate storage. This storage area could be the resource manager, an in-memory database or a cache.

commands

Define a command for use in an action, view, or workflow.

Organising your source

The Resource Interaction Model (RIM) language provides a scoping and reuse facility to help you organise your interaction model. Once you have identified events, commands or resources that you want to isolate or reuse you can simply wrap them in a domain and then use your model in a number of other source files.

domain TestDomain {
    use Common.Global.*
    use ONE.*
    
    rim ONE {
        commands
             NoopGET
        end
        initial resource A
             collection ENTITY
             view { NoopGET }
             GET -> TestDomain.TWO.B
        end
    }
    rim TWO {
        commands
             NoopGET
        end
        initial resource B
             collection ENTITY
             view { NoopGET }
             GET -> ONE.A
             GET -> A
        end
    }
}

domain

The RIM language uses the domain nomenclature to define a container for one or more rim objects. e.g. the example domain TestDomain above defines a domain with one resource interaction model (rim).

A domain MUST be given a unique name, it MUST define at least one rim.

rim

The RIM language uses the rim nomenclature to define a container for one or more resource objects. e.g. the example rim TestDomain.TWO above defines one resource called B.

A rim MUST be given a unique name, it MUST define at least one events, commands, or resource.

Grammar

The RIM grammar in EBNF notation can be found here RIMDsl.xtext. This grammar when used with XText can provide an Eclipse based editor for the RIM language.