A robust and pluggable client-side library for accessing services.
An SMD based service library.
All service endpoints are specified using JSON. The primary reasons for this are that JSON is lightweight, web native, and readable by any modern programming language. This allows us to write schema definitions once, and have them utilizable by both the client application code directly, and by server-side code that is typically written in Java or other languages. In order to maintain consistency, service schemas are written using a pre-defined set of JSON objects that specify the properties available to describe any component. For web services, this necessarily requires the use of two interdependent schema types. Descriptors of individual objects (request or response payloads and the subobjects contained with them) are written using JSONSchema, a formal IETF specification (draft) for describing JSON objects using JSON itself (http://tools.ietf.org/html/draft-zyp-json-schema-03). Numerous parsers and validators exist for JSONSchema, allowing easy adoption by client and server components. While JSONSchema is used to describe any JSON object, descriptors for service endpoints themselves are actually an example of an object instance that would be described using JSONSchema. In other words, JSONSchema specifies how to describe objects, and service schemas themselves are instances that have a JSONSchema file describing what they should look like (required properties such as url, query parameters, content-type, and so on). So the schema for a service endpoint is an object which itself can be validated using JSONSchema, whereas the payload schemas are direct JSONSchema files that describe the instance returned from the live service. Because the service endpoints are instances themselves, we must choose a schema format to reliably describe all of the elements for a RESTful service. Fortunately, others have already attempted this with some success. There are two primary public schemas available for describing REST services, and we intend support both of them.
Kris Zyp, the original author of JSONSchema, proposed a set of properties for defining RPC in general (including RESTful variants), and published this proposal in 2008 on a Google Group dedicated to its advancement. He called this schema a “Service Mapping Descriptor”, which is the term we use today to refer to these types of schemas in general. The Dojo Toolkit immediately supported this proposal, but subsequent work on it declined as REST in particular came to dominate practical service design. The original proposal’s support for describing many different RPC mechanisms led to a feeling of over-complexity as only a subset of the features were needed to describe RESTful services. The Google Group where this proposal was found is now offline, though we have transcribed the original content into a JSONSchema file that describes all of its properties. We currently support this as the first and originally more widely-used of SMD formats.
Fundamentally, the service subsystem requires only two outward mechanisms.
In practice, this subsystem will contain several other components in order to provide strong project decoupling, validation capabilities, and runtime flexibility. The components of the service subsystem are described below.
The service factory is responsible for using a schema to instantiate Service instance wrappers that handle the actual Ajax calls. The service factory is also where global configuration is specified, in order to make the component usable by any project and allow for test-specific setup.
SMD Readers are the processors of specific SMD schema types. The only one we currently support out-of-the-box is the Zyp format. Services will use public methods readers to request any information they need from the underlying document to construct a request.
The service object is an instance sent from the factory, containing methods corresponding to every service method defined in a given SMD. This object also has additional helper methods for managing and configuring the invocation of each method as needed.
Instances of a ServiceMethod are created for each method defined on the SMD, and attached to a Service. These methods are where the actual Ajax request happens under the hood.
The Request is a container that is returned from all asynchronous method invocations. This container includes the original service parameters so they can be inspected upon return, as well as a cancel mechanism in order to discard superseded calls.
A plugin is a function that is applied at some stage in the request/response process in order to provide modification or override of specific phases. In fact, all operations will be constructed using plugin chains, in order to ensure high configurability of the system. The “type” of a plugin indicates what phase it is applied within. Plugins can be specified globally (all services and all methods), at service level (all methods on an individual service), and method-specific (only one named method on one service). All plugins are applied in the order received, and can be added or removed at runtime as needed. Plugin types supported:
Special plugin types (not strictly part of the cycle)
Each plugin object has a name for identification, a type as described above, the function to execute, and a pointcut regular expression string or pattern regular expression string indicating what services and methods it is applied to (in the spirit of aspect-oriented programming). Circuits-js includes many plugins out of the box to meet common needs.
This software is licensed under the Apache 2.0 license (http://www.apache.org/licenses/LICENSE-2.0).