Use case 1: A client needs to process foo, which it does by creating a new resource which it can operate on. The client starts by making a POST request to /foos. This results in a new resource, a response with status code 201 (Created), relevant document and the Location header pointing to the URL of the new resource (/foos/123). The client can then operate on the new resource, e.g. reading its state at various points in time (GET), changing its state (PUT), or even discarding it (DELETE).
Use case 2: Continuing with use case 1, the client may need to process bar or baz, as part of the larger processing of foo. The client will attempt to create a new resource under /foos/123/bar or /foos/123/baz, but to do so the client must first determine the URL for either resource. This is done in a separate step, maybe in the response to the request that created /foos/123 or a subsequent operation against that resource (or in fact some other resource).
Use case 3: Continuing with use case 1, the client is able to operate on a collection of items that are part of the larger processing of foo. Those are exposed behind a URL like /foos/123/items/456, where 456 is the item number. The exact number of resources available depend on the number of items in that collection.
To achive these use cases we need the following features:
The above deal specifically with resources, but in addition we will also need a way to handle HTTP variables and query string parameters. We also expect the process engine to take care of common protocol details, such as status codes, redirection, cache control, content negotiation and encoding, HEAD and OPTIONs requests, etc.
Resources are declared in a scope, and a scope may declare any number of resources. A resource declaration consists of two properties, the resource name, which we use to reference the resource, and a relative path that denotes the relationship between this resource and other resources. Once instantiated, the value of the resource is an absolute URL.
The process can use resources in two ways. It can reference a resource for the purpose of receiving requests on that resource or a member of the collection denoted by the resource. It can also access the value of the resource (URL), for example, to send it as part of a message.
To access the value of the resource, we treat the resource as a read-only variable with the type xsd:uri. Expressions can access the resource as they would any other variable available in the scope, but cannot modify (assign to) its value. For that reason, all resources declared in a scope must have unique name and in addition no variable and resource declared in the same scope may have the same name.
A resource that specifies no path (or the empty path) will be instantiated using a URL unique to that process instance. A resource that specifies a static path will be instantiated by appending that path to the instance URL. A resource that specifies a path relative to another resource will be instantiated by appending that path to the URL of the other resource. We use the $ notation to reference another resource, so the path $foo/bar will append /bar to the URL denoted by the resource $foo.
To expose themselves as resources, the receive activity and event handler introduce four new properties. The method property specifies the HTTP method to accept, and the semantics of each HTTP method are described below. The resource property references a resource declaration available in the scope.
The instantiateResource property is true if the resource is instantiated by the receive activity or event handler, and false if the resource must be instantiated before the activity executes. This property can only be set to true when using the POST method, and is always true for the instantiating activity of the process.
When instantiateResource is false, the resource is instantiated first and the activity receives requests on that URL. When instantiateResource is true, the resource value is calculated and the activity receives requests on that URL. Once received, the resource is instantiated by appending a unique identifier to that URL. For example, the receive activity listens on the URL /foos, and upon receipt instantiates the resource to the URL /foos/123. In addition, the corresponding reply activity will set the status code to 201 (Created) and set the Location header to the resource URL.
The resourceIdentity activity names a variable that will be set to the member identity when receiving requests on behalf of a collection resource. When used in event handlers, the variable is implicitly defined in the implicit scope of the event handler and has the type xsd:string.
For example, if the resource is /foos/123/bars and the resourceIdentity is set to bar, then the activity will receive requests on the URL /foos/123/bars/{bar}, and the last part of the request URL path (the member identity {bar}) is assigned to the value of the variable bar.
The POST method has two uses, one involving the creation of a new resource, and the other involving processing of requests that do not map to any other HTTP method. The receive activity is coupled to a reply activity, and no other receive or wait is allowed to occur between the two.
When using the POST method to create a new resource, including in the instantiating activity of the process, the instantiateResource property is set to true, and the resource is instantiated by the activity. The reply activity uses the status code 201 (Created).
When using the POST method to process requests, the instantiate property is set to false. The reply activity sets the status code to 200 (OK), or if there is no document entity, to 204 (No Content).
The GET method has on side effects. To preserve this constraint only event handlers are allowed to use the GET method, and the event handler may only contain the reply activity. In addition, the event handler can only assign to variables declared in the implicit scope of the event handler, and faults occurring in the event handler are not propagated to the enclosing scope.
The process engine uses cache control to optimize the GET method by handling conditional GETs and setting the Last-Modified/ETag headers. These are set to detect any change in the state of the process instance (which excludes responding to a GET request).
The HEAD method is handled using receives for the GET method, without constructing a document entity in the response.
The PUT method is used to modify state. To be used successfully in combination with GET, the process engine supports conditional PUTs and returns 412 (Precondition Failed) if it detects a change in the process state since the corresponding GET.
The receive activity is coupled to a reply activity, and no other receive or wait is allowed to occur between the two. The reply activity sets the status code to 200 (OK), or if there is no document entity, to 204 (No Content).
The DELETE method does not have a corresponding reply activity and returns the status code 200 (OK).
The OPTIONS method is handled by the process engine.
Since all incoming requests must disambiguate a receive activity, no two receive activities can be outstanding on the same URL using the same method. This behavior is defined in term of URLs not resources, since it is possible for two resources to denote the same URL. It is also possible for the same resource to be used, once with the resourceIdentity property and once without, since those map two distinct URLs (/foos/something vs /foos).
The reply activity is matched to the corresponding receive activity based on the resource name.
Both receive and reply activities have access to an implicit message part called bodythat contains the internal representation of the document entity. Receive activities have access to an implicit message part called params, instantiated from the query string parameters. The XML representation of this part consists of the element Parameters, which maps query string parameters as follows: