| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.json.server">
- <title>Zend_Json_Server - JSON-RPC server</title>
- <para>
- <classname>Zend_Json_Server</classname> is a <ulink
- url="http://groups.google.com/group/json-rpc/">JSON-RPC</ulink>
- server implementation. It supports both the
- <ulink url="http://json-rpc.org/wiki/specification">JSON-RPC
- version 1 specification</ulink> as well as the
- <ulink url="http://groups.google.com/group/json-rpc/web/json-rpc-1-2-proposal">version 2 specification</ulink>;
- additionally, it provides a PHP implementation of the
- <ulink url="http://groups.google.com/group/json-schema/web/service-mapping-description-proposal">Service
- Mapping Description (SMD) specification</ulink>
- for providing service metadata to service consumers.
- </para>
- <para>
- JSON-RPC is a lightweight Remote Procedure Call protocol that utilizes
- JSON for its messaging envelopes. This JSON-RPC implementation follows
- PHP's <ulink
- url="http://us.php.net/manual/en/function.soap-soapserver-construct.php">SoapServer</ulink>
- API. This means that in a typical situation, you will simply:
- </para>
- <itemizedlist>
- <listitem><para>Instantiate the server object</para></listitem>
- <listitem><para>Attach one or more functions and/or classes/objects to
- the server object</para></listitem>
- <listitem><para>handle() the request</para></listitem>
- </itemizedlist>
- <para>
- <classname>Zend_Json_Server</classname> utilizes <xref linkend="zend.server.reflection" /> to
- perform reflection on any attached classes or functions, and uses that
- information to build both the SMD and enforce method call signatures. As
- such, it is imperative that any attached functions and/or class methods
- have full PHP docblocks documenting, minimally:
- </para>
- <itemizedlist>
- <listitem><para>All parameters and their expected variable types</para></listitem>
- <listitem><para>The return value variable type</para></listitem>
- </itemizedlist>
- <para>
- <classname>Zend_Json_Server</classname> listens for POST requests only at this
- time; fortunately, most JSON-RPC client implementations in the wild at
- the time of this writing will only POST requests as it is. This makes it
- simple to utilize the same server end point to both handle requests as
- well as to deliver the service SMD, as is shown in the next example.
- </para>
- <example id="zend.json.server.usage">
- <title>Zend_Json_Server Usage</title>
- <para>
- First, let's define a class we wish to expose via the JSON-RPC
- server. We'll call the class 'Calculator', and define methods for
- 'add', 'subtract', 'multiply', and 'divide':
- </para>
- <programlisting language="php"><![CDATA[
- /**
- * Calculator - sample class to expose via JSON-RPC
- */
- class Calculator
- {
- /**
- * Return sum of two variables
- *
- * @param int $x
- * @param int $y
- * @return int
- */
- public function add($x, $y)
- {
- return $x + $y;
- }
- /**
- * Return difference of two variables
- *
- * @param int $x
- * @param int $y
- * @return int
- */
- public function subtract($x, $y)
- {
- return $x - $y;
- }
- /**
- * Return product of two variables
- *
- * @param int $x
- * @param int $y
- * @return int
- */
- public function multiply($x, $y)
- {
- return $x * $y;
- }
- /**
- * Return the division of two variables
- *
- * @param int $x
- * @param int $y
- * @return float
- */
- public function divide($x, $y)
- {
- return $x / $y;
- }
- }
- ]]></programlisting>
- <para>
- Note that each method has a docblock with entries indicating each
- parameter and its type, as well as an entry for the return value.
- This is <emphasis>absolutely critical</emphasis> when utilizing
- <classname>Zend_Json_Server</classname> -- or any other server component in
- Zend Framework, for that matter.
- </para>
- <para>
- Now we'll create a script to handle the requests:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Json_Server();
- // Indicate what functionality is available:
- $server->setClass('Calculator');
- // Handle the request:
- $server->handle();
- ]]></programlisting>
- <para>
- However, this will not address the issue of returning an SMD so that
- the JSON-RPC client can autodiscover methods. That can be
- accomplished by determining the HTTP request method, and then
- specifying some server metadata:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Json_Server();
- $server->setClass('Calculator');
- if ('GET' == $_SERVER['REQUEST_METHOD']) {
- // Indicate the URL endpoint, and the JSON-RPC version used:
- $server->setTarget('/json-rpc.php')
- ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
- // Grab the SMD
- $smd = $server->getServiceMap();
- // Return the SMD to the client
- header('Content-Type: application/json');
- echo $smd;
- return;
- }
- $server->handle();
- ]]></programlisting>
- <para>
- If utilizing the JSON-RPC server with Dojo toolkit, you will also
- need to set a special compatibility flag to ensure that the two
- interoperate properly:
- </para>
- <programlisting language="php"><![CDATA[
- $server = new Zend_Json_Server();
- $server->setClass('Calculator');
- if ('GET' == $_SERVER['REQUEST_METHOD']) {
- $server->setTarget('/json-rpc.php')
- ->setEnvelope(Zend_Json_Server_Smd::ENV_JSONRPC_2);
- $smd = $server->getServiceMap();
- // Set Dojo compatibility:
- $smd->setDojoCompatible(true);
- header('Content-Type: application/json');
- echo $smd;
- return;
- }
- $server->handle();
- ]]></programlisting>
- </example>
- <sect2 id="zend.json.server.details">
- <title>Advanced Details</title>
- <para>
- While most functionality for <classname>Zend_Json_Server</classname> is
- spelled out in <xref linkend="zend.json.server.usage" />, more
- advanced functionality is available.
- </para>
- <sect3 id="zend.json.server.details.zendjsonserver">
- <title>Zend_Json_Server</title>
- <para>
- <classname>Zend_Json_Server</classname> is the core class in the JSON-RPC
- offering; it handles all requests and returns the response
- payload. It has the following methods:
- </para>
- <itemizedlist>
- <listitem><para><code>addFunction($function)</code>: Specify a
- userland function to attach to the server.</para></listitem>
- <listitem><para><code>setClass($class)</code>: Specify a class
- or object to attach to the server; all public methods of
- that item will be exposed as JSON-RPC methods.</para></listitem>
- <listitem><para><code>fault($fault = null, $code = 404, $data =
- null)</code>: Create and return a
- <classname>Zend_Json_Server_Error</classname> object.</para></listitem>
- <listitem><para><code>handle($request = false)</code>: Handle a
- JSON-RPC request; optionally, pass a
- <classname>Zend_Json_Server_Request</classname> object to utilize
- (creates one by default).</para></listitem>
- <listitem><para><code>getFunctions()</code>: Return a list of
- all attached methods.</para></listitem>
- <listitem><para><code>setRequest(Zend_Json_Server_Request
- $request)</code>: Specify a request object for the
- server to utilize.</para></listitem>
- <listitem><para><code>getRequest()</code>: Retrieve the request
- object used by the server.</para></listitem>
- <listitem><para><code>setResponse(Zend_Json_Server_Response
- $response)</code>: Set the response object for the
- server to utilize.</para></listitem>
- <listitem><para><code>getResponse()</code>: Retrieve the
- response object used by the server.</para></listitem>
- <listitem><para><code>setAutoEmitResponse($flag)</code>:
- Indicate whether the server should automatically emit
- the response and all headers; by default, this is
- true.</para></listitem>
- <listitem><para><code>autoEmitResponse()</code>: Determine if
- auto-emission of the response is enabled.</para></listitem>
- <listitem><para><code>getServiceMap()</code>: Retrieve the
- service map description in the form of a
- <classname>Zend_Json_Server_Smd</classname> object</para></listitem>
- </itemizedlist>
- </sect3>
- <sect3 id="zend.json.server.details.zendjsonserverrequest">
- <title>Zend_Json_Server_Request</title>
- <para>
- The JSON-RPC request environment is encapsulated in the
- <classname>Zend_Json_Server_Request</classname> object. This object allows
- you to set necessary portions of the JSON-RPC request, including
- the request ID, parameters, and JSON-RPC specification version.
- It has the ability to load itself via JSON or a set of options,
- and can render itself as JSON via the <code>toJson()</code>
- method.
- </para>
- <para>
- The request object has the following methods available:
- </para>
- <itemizedlist>
- <listitem><para><code>setOptions(array $options)</code>: Specify
- object configuration. <code>$options</code> may contain
- keys matching any 'set' method:
- <code>setParams()</code>, <code>setMethod()</code>,
- <code>setId()</code>, and
- <code>setVersion()</code>.</para></listitem>
- <listitem><para><code>addParam($value, $key = null)</code>: Add
- a parameter to use with the method call. Parameters can be
- just the values, or can optionally include the parameter
- name.</para></listitem>
- <listitem><para><code>addParams(array $params)</code>: Add
- multiple parameters at once; proxies to
- <code>addParam()</code></para></listitem>
- <listitem><para><code>setParams(array $params)</code>: Set all
- parameters at once; overwrites any existing
- parameters.</para></listitem>
- <listitem><para><code>getParam($index)</code>: Retrieve a
- parameter by position or name.</para></listitem>
- <listitem><para><code>getParams()</code>: Retrieve all
- parameters at once.</para></listitem>
- <listitem><para><code>setMethod($name)</code>: Set the method to
- call.</para></listitem>
- <listitem><para><code>getMethod()</code>: Retrieve the method
- that will be called.</para></listitem>
- <listitem><para><code>isMethodError()</code>: Determine whether
- or not the request is malformed and would result in an
- error.</para></listitem>
- <listitem><para><code>setId($name)</code>: Set the request
- identifier (used by the client to match requests to
- responses).</para></listitem>
- <listitem><para><code>getId()</code>: Retrieve the request
- identifier.</para></listitem>
- <listitem><para><code>setVersion($version)</code>: Set the
- JSON-RPC specification version the request conforms to.
- May be either '1.0' or '2.0'.</para></listitem>
- <listitem><para><code>getVersion()</code>: Retrieve the JSON-RPC
- specification version used by the
- request.</para></listitem>
- <listitem><para><code>loadJson($json)</code>: Load the request
- object from a JSON string.</para></listitem>
- <listitem><para><code>toJson()</code>: Render the request as
- a JSON string.</para></listitem>
- </itemizedlist>
- <para>
- An HTTP specific version is available via
- <classname>Zend_Json_Server_Request_Http</classname>. This class will
- retrieve the request via <code>php://input</code>, and allows
- access to the raw JSON via the <code>getRawJson()</code> method.
- </para>
- </sect3>
- <sect3 id="zend.json.server.details.zendjsonserverresponse">
- <title>Zend_Json_Server_Response</title>
- <para>
- The JSON-RPC response payload is encapsulated in the
- <classname>Zend_Json_Server_Response</classname> object. This object allows
- you to set the return value of the request, whether or not the
- response is an error, the request identifier, the JSON-RPC
- specification version the response conforms to, and optionally
- the service map.
- </para>
- <para>
- The response object has the following methods available:
- </para>
- <itemizedlist>
- <listitem><para><code>setResult($value)</code>: Set the response
- result.</para></listitem>
- <listitem><para><code>getResult()</code>: Retrieve the response
- result.</para></listitem>
- <listitem><para><code>setError(Zend_Json_Server_Error
- $error)</code>: Set an error object. If set, this will be
- used as the response when serializing to JSON.</para></listitem>
- <listitem><para><code>getError()</code>: Retrieve the error
- object, if any.</para></listitem>
- <listitem><para><code>isError()</code>: Whether or not the
- response is an error response.</para></listitem>
- <listitem><para><code>setId($name)</code>: Set the request
- identifier (so the client may match the response with
- the original request).</para></listitem>
- <listitem><para><code>getId()</code>: Retrieve the request
- identifier.</para></listitem>
- <listitem><para><code>setVersion($version)</code>: Set the
- JSON-RPC version the response conforms to.</para></listitem>
- <listitem><para><code>getVersion()</code>: Retrieve the JSON-RPC
- version the response conforms to.</para></listitem>
- <listitem><para><code>toJson()</code>: Serialize the response to
- JSON. If the response is an error response, serializes the
- error object.</para></listitem>
- <listitem><para><code>setServiceMap($serviceMap)</code>: Set the
- service map object for the response.</para></listitem>
- <listitem><para><code>getServiceMap()</code>: Retrieve the
- service map object, if any.</para></listitem>
- </itemizedlist>
- <para>
- An HTTP specific version is available via
- <classname>Zend_Json_Server_Response_Http</classname>. This class will
- send the appropriate HTTP headers as well as serialize the
- response as JSON.
- </para>
- </sect3>
- <sect3 id="zend.json.server.details.zendjsonservererror">
- <title>Zend_Json_Server_Error</title>
- <para>
- JSON-RPC has a special format for reporting error conditions.
- All errors need to provide, minimally, an error message and error
- code; optionally, they can provide additional data, such as a
- backtrace.
- </para>
- <para>
- Error codes are derived from those recommended by <ulink
- url="http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php">the
- XML-RPC EPI project</ulink>. <classname>Zend_Json_Server</classname>
- appropriately assigns the code based on the error condition. For
- application exceptions, the code '-32000' is used.
- </para>
- <para>
- <classname>Zend_Json_Server_Error</classname> exposes the following
- methods:
- </para>
- <itemizedlist>
- <listitem><para><code>setCode($code)</code>: Set the error code;
- if the code is not in the accepted XML-RPC error code range,
- -32000 will be assigned.</para></listitem>
- <listitem><para><code>getCode()</code>: Retrieve the current
- error code.</para></listitem>
- <listitem><para><code>setMessage($message)</code>: Set the error
- message.</para></listitem>
- <listitem><para><code>getMessage()</code>: Retrieve the current
- error message.</para></listitem>
- <listitem><para><code>setData($data)</code>: Set auxiliary data
- further qualifying the error, such as a
- backtrace.</para></listitem>
- <listitem><para><code>getData()</code>: Retrieve any current
- auxiliary error data.</para></listitem>
- <listitem><para><code>toArray()</code>: Cast the error to an
- array. The array will contain the keys 'code', 'message',
- and 'data'.</para></listitem>
- <listitem><para><code>toJson()</code>: Cast the error to a
- JSON-RPC error representation.</para></listitem>
- </itemizedlist>
- </sect3>
- <sect3 id="zend.json.server.details.zendjsonserversmd">
- <title>Zend_Json_Server_Smd</title>
- <para>
- SMD stands for Service Mapping Description, a JSON schema that
- defines how a client can interact with a particular web service.
- At the time of this writing, the <ulink
- url="http://groups.google.com/group/json-schema/web/service-mapping-description-proposal">specification</ulink>
- has not yet been formally ratified, but it is in use already
- within Dojo toolkit as well as other JSON-RPC consumer clients.
- </para>
- <para>
- At its most basic, a Service Mapping Description indicates the
- method of transport (POST, GET, TCP/IP, etc), the request
- envelope type (usually based on the protocol of the server), the
- target URL of the service provider, and a map of services
- available. In the case of JSON-RPC, the service map is a list of
- available methods, which each method documenting the available
- parameters and their types, as well as the expected return value
- type.
- </para>
- <para>
- <classname>Zend_Json_Server_Smd</classname> provides an object oriented
- way to build service maps. At its most basic, you pass it
- metadata describing the service using mutators, and specify
- services (methods and functions).
- </para>
- <para>
- The service descriptions themselves are typically instances of
- <classname>Zend_Json_Server_Smd_Service</classname>; you can also pass all
- information as an array to the various service mutators in
- <classname>Zend_Json_Server_Smd</classname>, and it will instantiate a
- service object for you. The service objects contain information
- such as the name of the service (typically the function or
- method name), the parameters (names, types, and position), and
- the return value type. Optionally, each service can have its own
- target and envelope, though this functionality is rarely used.
- </para>
- <para>
- <classname>Zend_Json_Server</classname> actually does all of this behind
- the scenes for you, by using reflection on the attached classes
- and functions; you should create your own service maps only if
- you need to provide custom functionality that class and function
- introspection cannot offer.
- </para>
- <para>
- Methods available in <classname>Zend_Json_Server_Smd</classname> include:
- </para>
- <itemizedlist>
- <listitem><para><code>setOptions(array $options)</code>: Setup
- an SMD object from an array of options. All mutators
- (methods beginning with 'set') can be used as
- keys.</para></listitem>
- <listitem><para><code>setTransport($transport)</code>: Set the
- transport used to access the service; only POST is
- currently supported.</para></listitem>
- <listitem><para><code>getTransport()</code>: Get the current
- service transport.</para></listitem>
- <listitem><para><code>setEnvelope($envelopeType)</code>: Set the
- request envelope that should be used to access the
- service. Currently, supports the constants
- <classname>Zend_Json_Server_Smd::ENV_JSONRPC_1</classname> and
- <classname>Zend_Json_Server_Smd::ENV_JSONRPC_2</classname>.</para></listitem>
- <listitem><para><code>getEnvelope()</code>: Get the current
- request envelope.</para></listitem>
- <listitem><para><code>setContentType($type)</code>: Set the
- content type requests should use (by default, this is
- 'application/json').</para></listitem>
- <listitem><para><code>getContentType()</code>: Get the current
- content type for requests to the service.</para></listitem>
- <listitem><para><code>setTarget($target)</code>: Set the URL
- endpoint for the service.</para></listitem>
- <listitem><para><code>getTarget()</code>: Get the URL endpoint
- for the service.</para></listitem>
- <listitem><para><code>setId($id)</code>: Typically, this is the
- URL endpoint of the service (same as the
- target).</para></listitem>
- <listitem><para><code>getId()</code>: Retrieve the service ID
- (typically the URL endpoint of the
- service).</para></listitem>
- <listitem><para><code>setDescription($description)</code>: Set a
- service description (typically narrative information
- describing the purpose of the service).</para></listitem>
- <listitem><para><code>getDescription()</code>: Get the service
- description.</para></listitem>
- <listitem><para><code>setDojoCompatible($flag)</code>: Set a
- flag indicating whether or not the SMD is compatible
- with Dojo toolkit. When true, the generated JSON SMD
- will be formatted to comply with the format that Dojo's
- JSON-RPC client expects.</para></listitem>
- <listitem><para><code>isDojoCompatible()</code>: Returns the
- value of the Dojo compatibility flag (false, by
- default).</para></listitem>
- <listitem><para><code>addService($service)</code>: Add a service
- to the map. May be an array of information to pass to
- the constructor of
- <classname>Zend_Json_Server_Smd_Service</classname>, or an
- instance of that class.</para></listitem>
- <listitem><para><code>addServices(array $services)</code>: Add
- multiple services at once.</para></listitem>
- <listitem><para><code>setServices(array $services)</code>: Add
- multiple services at once, overwriting any previously
- set services.</para></listitem>
- <listitem><para><code>getService($name)</code>: Get a service by
- its name.</para></listitem>
- <listitem><para><code>getServices()</code>: Get all attached
- services.</para></listitem>
- <listitem><para><code>removeService($name)</code>: Remove a
- service from the map.</para></listitem>
- <listitem><para><code>toArray()</code>: Cast the service map to
- an array.</para></listitem>
- <listitem><para><code>toDojoArray()</code>: Cast the service map
- to an array compatible with Dojo Toolkit.</para></listitem>
- <listitem><para><code>toJson()</code>: Cast the service map to a
- JSON representation.</para></listitem>
- </itemizedlist>
- <para>
- <classname>Zend_Json_Server_Smd_Service</classname> has the following
- methods:
- </para>
- <itemizedlist>
- <listitem><para><code>setOptions(array $options)</code>: Set
- object state from an array. Any mutator (methods
- beginning with 'set') may be used as a key and set via
- this method.</para></listitem>
- <listitem><para><code>setName($name)</code>: Set the service
- name (typically, the function or method name).</para></listitem>
- <listitem><para><code>getName()</code>: Retrieve the service
- name.</para></listitem>
- <listitem><para><code>setTransport($transport)</code>: Set the
- service transport (currently, only transports supported
- by <classname>Zend_Json_Server_Smd</classname> are allowed).</para></listitem>
- <listitem><para><code>getTransport()</code>: Retrieve the
- current transport.</para></listitem>
- <listitem><para><code>setTarget($target)</code>: Set the URL
- endpoint of the service (typically, this will be the
- same as the overall SMD to which the service is
- attached).</para></listitem>
- <listitem><para><code>getTarget()</code>: Get the URL endpoint
- of the service.</para></listitem>
- <listitem><para><code>setEnvelope($envelopeType)</code>: Set the
- service envelope (currently, only envelopes supported
- by <classname>Zend_Json_Server_Smd</classname> are allowed).</para></listitem>
- <listitem><para><code>getEnvelope()</code>: Retrieve the service
- envelope type.</para></listitem>
- <listitem><para><code>addParam($type, array $options = array(),
- $order = null)</code>: Add a parameter to the
- service. By default, only the parameter type is
- necessary. However, you may also specify the order, as
- well as options such as:</para>
- <itemizedlist>
- <listitem><para><emphasis>name</emphasis>: the parameter
- name</para></listitem>
- <listitem><para><emphasis>optional</emphasis>: whether
- or not the parameter is optional</para></listitem>
- <listitem><para><emphasis>default</emphasis>: a default
- value for the parameter</para></listitem>
- <listitem><para><emphasis>description</emphasis>: text
- describing the parameter</para></listitem>
- </itemizedlist>
- </listitem>
- <listitem><para><code>addParams(array $params)</code>: Add
- several parameters at once; each param should be an assoc
- array containing minimally the key 'type' describing the
- parameter type, and optionally the key 'order'; any other
- keys will be passed as <code>$options</code> to
- <code>addOption()</code>.</para></listitem>
- <listitem><para><code>setParams(array $params)</code>: Set many
- parameters at once, overwriting any existing
- parameters.</para></listitem>
- <listitem><para><code>getParams()</code>: Retrieve all currently
- set parameters.</para></listitem>
- <listitem><para><code>setReturn($type)</code>: Set the return
- value type of the service.</para></listitem>
- <listitem><para><code>getReturn()</code>: Get the return value
- type of the service.</para></listitem>
- <listitem><para><code>toArray()</code>: Cast the service to an
- array.</para></listitem>
- <listitem><para><code>toJson()</code>: Cast the service to a
- JSON representation.</para></listitem>
- </itemizedlist>
- </sect3>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|