View Source

<ac:macro ac:name="unmigrated-inline-wiki-markup"><ac:plain-text-body><![CDATA[{zone-template-instance:ZFDEV:Zend Proposal Zone Template}

{zone-data:component-name}
Zend_Json_Server
{zone-data}

{zone-data:proposer-list}
[Matthew Weier O'Phinney|mailto:matthew@zend.com]
[~ralph] Zend Liaison
{zone-data}

{zone-data:revision}
0.9 - 9 April 2008: Initial proposal
1.0 - 10 April 2008: Opening for Community Review
{zone-data}

{zone-data:overview}
JSON-RPC provides a standard specification for using JSON as a transmission medium for an RPC server. The only reasonable solution for Zend_Json_Server, in order to be able to interoperate as much as possible with clients and other JSON-RPC services, is to follow this specification.

Currently, there are several versions of the specification. 1.0 is widely used, and is an accepted standard. 1.1 exists in three separate proposals and has been abandoned; 1.2 has been debated heavily, and has been re-proposed as 2.0; 2.0 is close to completion, but has several important questions to answer before approval (system descriptions being one important area). This proposal will support version 1.0 initially, leaving room for support of additional versions of the specification.

While the 1.0 specification has no requirement that servers implement a system.describe method (required in the later working drafts), many clients now require that a particular JSON-RPC server have a Service Mapping Description (SMD) file to describe their service. This file reports the server version, URL, and methods in a standardized JSON format that closely follows the proposed system.describe format of later specification revisions. This proposal will address the SMD format as well.

JSON-RPC does not specify a transport. The server can be agnostic to where the request is coming from, so long as the server can assemble the information it needs to form the request. SMD can be used to indicate the transport and request method. However, if the service listens to GET requests, this adds an extra onus on the server to build the request properly based on the endpoint and the query string provided. To simplify operation of the server, and because the server will be considered a single endpoint, we will utilize only POST requests, and expect a JSON object in the raw post body.

All requests include a unique identifier so that responses can be paired with the requests asynchronously. However, JSON-RPC also has the concept of "notifications" -- requests that do not require a response. Such requests are made with a null request identifier.
{zone-data}

{zone-data:references}
* [JSON-RPC 1.0 specification|http://json-rpc.org/wiki/specification]
* [JSON-RPC 2.0 specification|http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal]
* [Service Mapping Description Proposal|http://groups.google.com/group/json-schema/web/service-mapping-description-proposal]
{zone-data}

{zone-data:requirements}
* MUST only respond to POST requests
* MUST allow JSON-RPC Notification requests
** SHOULD return 204 HTTP response w/o content for forward compatability
* MUST allow retrieval of parameters from Request and Response objects
* MUST allow retrieval of raw JSON request/response
* MUST provide functionality to create Service Mapping Description
** MUST implement Service Mapping Description format from json-schema group
** MUST support optional parameters
** MUST support default values
** SHOULD allow specifying more parameters than signature specifies
** SHOULD allow specifying parity of server
** SHOULD autodetermine if requested via .smd extension
** SHOULD have accessors for SMD metadata
** SHOULD cache to local filesystem on request
* SHOULD use v2.0 specifcation error codes
* SHOULD send appropriate HTTP response headers for forward compatability
* COULD provide functionality to facilitate JS object type hinting
* COULD provide namespacing of classes via '-'
{zone-data}

{zone-data:dependencies}
* Zend_Exception
* Zend_Server_Interface
* Zend_Server_Reflection
{zone-data}

{zone-data:operation}
A client would request the SMD using a .smd extension in the URL or by calling system.describe. The server would then perform introspection on the attached classes, objects, and functions to generate the SMD for the client (optionally pulling from a cache for this information).

When a client performs a JSON-RPC request, the server would determine the type of request. For a notification, it would send an immediate HTTP 204 response with no content, and buffer all additional output to ensure no additional data is sent to the client. For all other requests, it would process the request and attempt to return a JSON-RPC response.

Should an error or exception occur, the server would return an error response with the appropriate error code and error details.
{zone-data}

{zone-data:milestones}
* Milestone 1: \[DONE\] Create this proposal
* Milestone 2: \[DONE\] Solicit community feedback and incorporate
* Milestone 3: \[DONE\] Create functionality to generate SMD
* Milestone 4: \[DONE\] Create server, request, and response classes
* Milestone 5: Proposal acceptance
* Milestone 6: Write documentation

{zone-data}

{zone-data:class-list}
* Zend_Json_Server
* Zend_Json_Server_Request
* Zend_Json_Server_Response
* Zend_Json_Server_Error
* Zend_Json_Server_Smd
* Zend_Json_Server_Smd_Service
{zone-data}

{zone-data:use-cases}
||UC-01||
h4. Basic Usage
{code:php}
$server = new Zend_Json_Server();

// Specify SMD metadata
$server->setTransport(Zend_Json_Server::TRANSPORT_POST)
->setTarget('/json-rpc/service')
->setId('/json-rpc/service');

// Specify class to serve
$server->setClass('FooService');

// Allow auto-emitting response
$server->setAutoEmitResponse(true);

// Handle request
$server->handle();
{code}

||UC-02||
h4. Retrieve and Store SMD
{code:php}
$server = new Zend_Json_Server();

// Specify SMD metadata
$server->setTransport(Zend_Json_Server::TRANSPORT_POST)
->setTarget('/json-rpc/service')
->setId('/json-rpc/service');

// Specify class to serve
$server->setClass('FooService');

$smd = $server->getServiceMap();

file_put_contents($filename, $smd->toJson());
{code}
{zone-data}

{zone-data:skeletons}
*NOTE:* Working and tested code may now be found in SVN at [http://framework.zend.com/svn/framework/branch/user/matthew/zend_json_server/]

h4. Zend_Json_Server
{code:php}
class Zend_Json_Server implements Zend_Server_Interface
{
const VERSION_1 = '1.0';
const VERSION_2 = '2.0';

public function addFunction($function, $namespace = '');
public function setClass($class, $namespace = '', $argv = null);
public function fault($fault = null, $code = 404);
public function handle($request = false);
public function getFunctions();
public function loadFunctions($definition);
public function setPersistence($mode);

// request/response accessors
public function setRequest(Zend_Json_Server_Request $request);
public function getRequest();
public function setResponse(Zend_Json_Server_Response $response);
public function getResponse();

// whether or not to immediately send the response
public function setAutoEmitResponse($flag);

// overloading for SMD metadata
public function __call($method, $args);

// retrieve SMD
public function getServiceMap();
}
{code}

h4. Zend_Json_Server_Request
{code:php}
class Zend_Json_Server_Request
{
// Add params to the request
// allow adding just value or key/value pair
public function addParam($spec, $value = null);
public function addParams(array $params);
public function setParams(array $params);
public function getParam($index);
public function getParams();

// RPC method to call
public function setMethod($name);
public function getMethod();

// id of request
public function setId($name);
public function getId();

// Version of JSON-RPC to adhere to
// Populates 'jsonrpc' parameter on requests honoring 2.0 spec
public function setVersion($version);
public function getVersion();

// Get JSON representation of request
public function toJson();

// Proxy to toJson()
public function __toString();
}
{code}

h4. Zend_Json_Server_Response
{code:php}
class Zend_Json_Server_Response
{
// Result of call
public function setResult($value);
public function getResult();

// RPC error, if response results in fault
public function setError(Zend_Json_Server_Error $error);
public function getError();

// id of request
public function setId($name);
public function getId();

// Version of JSON-RPC response adheres to
// Populates 'jsonrpc' parameter on responses honoring 2.0 spec
public function setVersion($version);
public function getVersion();

// Render response as JSON-RPC object
public function toJson();

// Proxy to toJson()
public function __toString();
}
{code}

h4. Zend_Json_Server_Error
{code:php}
class Zend_Json_Server_Error
{
const ERROR_PARSE = -32768;
const ERROR_INVALID_REQUEST = -32600;
const ERROR_INVALID_METHOD = -32601;
const ERROR_INVALID_PARAMS = -32602;
const ERROR_INTERNAL = -32603;
const ERROR_OTHER = -32000;

// Error code
public function setCode($code);
public function getCode();

// Error message
public function setMessage($message);
public function getMessage();

// Error data
public function setData($data);
public function getData();

// Render error as JSON-RPC error object
public function toJson();

// Proxy to toJson()
public function __toString();
}
{code}

h4. Zend_Json_Server_Smd
{code:php}
class Zend_Json_Server_Smd
{
// Transport
// Likely will limit to POST
public function setTransport($transport);
public function getTransport();

// Set return envelope
// Will likely restrict to JSON-RPC-1.1 and JSON-RPC-1.2
public function setEnvelope($envelopeType);
public function getEnvelope();

// Content-Type of response; default to application/json
public function setContentType($type);
public function getContentType();

// Target of service (url or IP address)
public function setTarget($target);
public function getTarget();

// Id of service (usu. url)
public function setId($Id);
public function getId();

// Add and retrieve SMD service descriptions
// Allow specifying SMD service as either array of service
// data or as SMD service object
public function addService(Zend_Json_Server_Smd_Service|array $service);
public function addServices(array $services);
public function setServices(array $services);
public function getService($name);
public function getServices();

// Factory for creating service description from array
public function createService(array $serviceData);

// Emit as JSON
public function toJson();

// Proxy to toJson()
public function __toString();
}
{code}

h4. Zend_Json_Server_Smd_Service
{code:php}
class Zend_Json_Server_Smd_Service
{
// Service name (RPC method name)
public function setName($name);
public function getName();

// Transport
// Will likely limit to POST
public function setTransport($transport);
public function getTransport();

// Target of service (url or IP address)
public function setTarget($target);
public function getTarget();

// Set return envelope
// Will likely restrict to JSON-RPC-1.1 and JSON-RPC-1.2
public function setEnvelope($envelopeType);
public function getEnvelope();

// Add a param
// Parameter type is required and may be a string type or array of types.
// Other options follow json-schema property definition and are optional.
public function addParam($type, array $options = null);
public function addParams(array $params);
public function setParams(array $params);
public function getParams();

// Return type
// At some point, should allow specifying JSON schema
public function setReturns($type);
public function getReturns();

// Emit as JSON
public function toJson();

// Proxy to toJson()
public function __toString();
}
{code}
{zone-data}

{zone-template-instance}]]></ac:plain-text-body></ac:macro>