TigerZF
🌐Español

39.5. Zend_Json_Server - Servidor JSON-RPC

Zend_Json_Server es una implementación de servidor JSON-RPC. Admite tanto la especificación de la versión 1 de JSON-RPC como la especificación de la versión 2; además, proporciona una implementación en PHP de la especificación Service Mapping Description (SMD) para proporcionar metadatos del servicio a los consumidores del mismo.

JSON-RPC es un protocolo ligero de llamada a procedimiento remoto que utiliza JSON para sus envolturas de mensajes. Esta implementación de JSON-RPC sigue la API SoapServer de PHP. Esto significa que, en una situación típica, simplemente deberá:

  • Instanciar el objeto servidor

  • Adjuntar una o más funciones y/o clases/objetos al objeto servidor

  • Ejecutar handle() para la petición

Zend_Json_Server utiliza Zend_Server_Reflection para realizar reflexión sobre cualquier clase o función adjunta, y usa esa información para construir el SMD y aplicar las firmas de llamada de los métodos. Por ello, es imperativo que cualquier función y/o método de clase adjunto tenga bloques de documentación completos de PHP que documenten, como mínimo:

  • Todos los parámetros y sus tipos de variable esperados

  • El tipo de variable del valor de retorno

Zend_Json_Server por el momento solo escucha peticiones POST; afortunadamente, la mayoría de las implementaciones de cliente JSON-RPC existentes en el momento de escribir esto solo hacen POST de todos modos. Esto hace sencillo utilizar el mismo punto final del servidor tanto para manejar peticiones como para entregar el SMD del servicio, como se muestra en el siguiente ejemplo.

Ejemplo 39.1. Uso de Zend_Json_Server

Primero, definamos una clase que queremos exponer mediante el servidor JSON-RPC. Llamaremos a la clase 'Calculator', y definiremos métodos para 'add', 'subtract', 'multiply' y 'divide':

/**
 * 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;
    }
}

Observe que cada método tiene un bloque de documentación con entradas que indican cada parámetro y su tipo, así como una entrada para el valor de retorno. Esto es absolutamente fundamental al utilizar Zend_Json_Server o cualquier otro componente de servidor de Zend Framework, dicho sea de paso.

Ahora crearemos un script para manejar las peticiones:

$server = new Zend_Json_Server();

// Indicate what functionality is available:
$server->setClass('Calculator');

// Handle the request:
$server->handle();

Sin embargo, esto no resolverá el problema de devolver un SMD para que el cliente JSON-RPC pueda autodescubrir los métodos. Eso puede lograrse determinando el método de petición HTTP, y luego especificando algunos metadatos del servidor:

$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();

Si utiliza el servidor JSON-RPC con Dojo toolkit, también necesitará establecer un indicador especial de compatibilidad para asegurar que ambos interoperen correctamente:

$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();

39.5.1. Detalles avanzados

Aunque la mayor parte de la funcionalidad de Zend_Json_Server está explicada en esta sección, hay disponible funcionalidad más avanzada.

39.5.1.1. Zend_Json_Server

Zend_Json_Server es la clase núcleo de la oferta JSON-RPC; maneja todas las peticiones y devuelve la carga de la respuesta. Tiene los siguientes métodos:

  • addFunction($function): Especifica una función de usuario para adjuntar al servidor.

  • setClass($class): Especifica una clase u objeto para adjuntar al servidor; todos los métodos públicos de ese elemento se expondrán como métodos JSON-RPC.

  • fault($fault = null, $code = 404, $data = null): Crea y devuelve un objeto Zend_Json_Server_Error.

  • handle($request = false): Maneja una petición JSON-RPC; opcionalmente, pase un objeto Zend_Json_Server_Request para utilizarlo (crea uno por defecto).

  • getFunctions(): Devuelve una lista de todos los métodos adjuntos.

  • setRequest(Zend_Json_Server_Request $request): Especifica un objeto de petición para que lo utilice el servidor.

  • getRequest(): Recupera el objeto de petición utilizado por el servidor.

  • setResponse(Zend_Json_Server_Response $response): Establece el objeto de respuesta que utilizará el servidor.

  • getResponse(): Recupera el objeto de respuesta utilizado por el servidor.

  • setAutoEmitResponse($flag): Indica si el servidor debe emitir automáticamente la respuesta y todas las cabeceras; por defecto, esto es TRUE.

  • autoEmitResponse(): Determina si la emisión automática de la respuesta está habilitada.

  • getServiceMap(): Recupera la descripción del mapa de servicio en forma de un objeto Zend_Json_Server_Smd

39.5.1.2. Zend_Json_Server_Request

El entorno de petición JSON-RPC está encapsulado en el objeto Zend_Json_Server_Request. Este objeto le permite establecer las partes necesarias de la petición JSON-RPC, incluyendo el ID de petición, los parámetros y la versión de la especificación JSON-RPC. Tiene la capacidad de cargarse a sí mismo mediante JSON o un conjunto de opciones, y puede renderizarse a sí mismo como JSON mediante el método toJson().

El objeto de petición tiene disponibles los siguientes métodos:

  • setOptions(array $options): Especifica la configuración del objeto. $options puede contener claves que coincidan con cualquier método 'set': setParams(), setMethod(), setId(), y setVersion().

  • addParam($value, $key = null): Añade un parámetro para usar con la llamada al método. Los parámetros pueden ser solo los valores, o pueden opcionalmente incluir el nombre del parámetro.

  • addParams(array $params): Añade múltiples parámetros a la vez; delega en addParam()

  • setParams(array $params): Establece todos los parámetros a la vez; sobrescribe cualquier parámetro existente.

  • getParam($index): Recupera un parámetro por posición o nombre.

  • getParams(): Recupera todos los parámetros a la vez.

  • setMethod($name): Establece el método a llamar.

  • getMethod(): Recupera el método que se llamará.

  • isMethodError(): Determina si la petición está mal formada y provocaría un error.

  • setId($name): Establece el identificador de petición (usado por el cliente para hacer coincidir las peticiones con las respuestas).

  • getId(): Recupera el identificador de la petición.

  • setVersion($version): Establece la versión de la especificación JSON-RPC a la que se ajusta la petición. Puede ser '1.0' o '2.0'.

  • getVersion(): Recupera la versión de la especificación JSON-RPC utilizada por la petición.

  • loadJson($json): Carga el objeto de petición a partir de una cadena JSON.

  • toJson(): Renderiza la petición como una cadena JSON.

Hay disponible una versión específica para HTTP mediante Zend_Json_Server_Request_Http. Esta clase recuperará la petición mediante php://input, y permite acceder al JSON en bruto mediante el método getRawJson().

39.5.1.3. Zend_Json_Server_Response

La carga de respuesta JSON-RPC está encapsulada en el objeto Zend_Json_Server_Response. Este objeto le permite establecer el valor de retorno de la petición, si la respuesta es un error o no, el identificador de la petición, la versión de la especificación JSON-RPC a la que se ajusta la respuesta, y opcionalmente el mapa de servicio.

El objeto de respuesta tiene disponibles los siguientes métodos:

  • setResult($value): Establece el resultado de la respuesta.

  • getResult(): Recupera el resultado de la respuesta.

  • setError(Zend_Json_Server_Error $error): Establece un objeto de error. Si se establece, se usará como la respuesta al serializar a JSON.

  • getError(): Recupera el objeto de error, si existe alguno.

  • isError(): Indica si la respuesta es o no una respuesta de error.

  • setId($name): Establece el identificador de petición (para que el cliente pueda hacer coincidir la respuesta con la petición original).

  • getId(): Recupera el identificador de la petición.

  • setVersion($version): Establece la versión de JSON-RPC a la que se ajusta la respuesta.

  • getVersion(): Recupera la versión de JSON-RPC a la que se ajusta la respuesta.

  • toJson(): Serializa la respuesta a JSON. Si la respuesta es una respuesta de error, serializa el objeto de error.

  • setServiceMap($serviceMap): Establece el objeto de mapa de servicio para la respuesta.

  • getServiceMap(): Recupera el objeto de mapa de servicio, si existe alguno.

Hay disponible una versión específica para HTTP mediante Zend_Json_Server_Response_Http. Esta clase enviará las cabeceras HTTP apropiadas, así como serializará la respuesta como JSON.

39.5.1.4. Zend_Json_Server_Error

JSON-RPC tiene un formato especial para informar condiciones de error. Todos los errores deben proporcionar, como mínimo, un mensaje de error y un código de error; opcionalmente, pueden proporcionar datos adicionales, como un backtrace.

Los códigos de error se derivan de los recomendados por el proyecto XML-RPC EPI. Zend_Json_Server asigna el código apropiadamente según la condición de error. Para excepciones de la aplicación, se utiliza el código '-32000'.

Zend_Json_Server_Error expone los siguientes métodos:

  • setCode($code): Establece el código de error; si el código no está en el rango de códigos de error XML-RPC aceptado, se asignará -32000.

  • getCode(): Recupera el código de error actual.

  • setMessage($message): Establece el mensaje de error.

  • getMessage(): Recupera el mensaje de error actual.

  • setData($data): Establece datos auxiliares que califican aún más el error, como un backtrace.

  • getData(): Recupera cualquier dato auxiliar de error actual.

  • toArray(): Convierte el error en un array. El array contendrá las claves 'code', 'message' y 'data'.

  • toJson(): Convierte el error en una representación de error JSON-RPC.

39.5.1.5. Zend_Json_Server_Smd

SMD significa Service Mapping Description, un esquema JSON que define cómo un cliente puede interactuar con un servicio web en particular. En el momento de escribir esto, la especificación aún no ha sido ratificada formalmente, pero ya se utiliza dentro de Dojo toolkit, así como en otros clientes consumidores de JSON-RPC.

En su forma más básica, una Service Mapping Description indica el método de transporte (POST, GET, TCP/IP, etc.), el tipo de envoltura de la petición (normalmente basado en el protocolo del servidor), la URL objetivo del proveedor del servicio, y un mapa de los servicios disponibles. En el caso de JSON-RPC, el mapa de servicio es una lista de métodos disponibles, documentando cada método los parámetros disponibles y sus tipos, así como el tipo de valor de retorno esperado.

Zend_Json_Server_Smd proporciona una forma orientada a objetos de construir mapas de servicio. En su forma más básica, se le pasan metadatos que describen el servicio mediante mutadores, y se especifican los servicios (métodos y funciones).

Las descripciones de servicio en sí mismas son típicamente instancias de Zend_Json_Server_Smd_Service; también puede pasar toda la información como un array a los distintos mutadores de servicio en Zend_Json_Server_Smd, y este instanciará un objeto de servicio por usted. Los objetos de servicio contienen información como el nombre del servicio (típicamente el nombre de la función o del método), los parámetros (nombres, tipos y posición), y el tipo del valor de retorno. Opcionalmente, cada servicio puede tener su propio objetivo y envoltura, aunque esta funcionalidad se usa raramente.

Zend_Json_Server en realidad hace todo esto por usted entre bastidores, usando reflexión sobre las clases y funciones adjuntas; debería crear sus propios mapas de servicio solo si necesita proporcionar funcionalidad personalizada que la introspección de clases y funciones no pueda ofrecer.

Entre los métodos disponibles en Zend_Json_Server_Smd se incluyen:

  • setOptions(array $options): Configura un objeto SMD a partir de un array de opciones. Todos los mutadores (métodos que comienzan con 'set') pueden usarse como claves.

  • setTransport($transport): Establece el transporte usado para acceder al servicio; actualmente solo se admite POST.

  • getTransport(): Obtiene el transporte de servicio actual.

  • setEnvelope($envelopeType): Establece la envoltura de petición que debe usarse para acceder al servicio. Actualmente, admite las constantes Zend_Json_Server_Smd::ENV_JSONRPC_1 y Zend_Json_Server_Smd::ENV_JSONRPC_2.

  • getEnvelope(): Obtiene la envoltura de petición actual.

  • setContentType($type): Establece el tipo de contenido que deben usar las peticiones (por defecto, es 'application/json').

  • getContentType(): Obtiene el tipo de contenido actual para las peticiones al servicio.

  • setTarget($target): Establece el punto final URL para el servicio.

  • getTarget(): Obtiene el punto final URL para el servicio.

  • setId($id): Típicamente, este es el punto final URL del servicio (igual que el objetivo).

  • getId(): Recupera el ID del servicio (típicamente el punto final URL del servicio).

  • setDescription($description): Establece una descripción del servicio (típicamente información narrativa que describe el propósito del servicio).

  • getDescription(): Obtiene la descripción del servicio.

  • setDojoCompatible($flag): Establece un indicador que indica si el SMD es o no compatible con Dojo toolkit. Cuando es TRUE, el JSON SMD generado se formateará para cumplir con el formato que espera el cliente JSON-RPC de Dojo.

  • isDojoCompatible(): Devuelve el valor del indicador de compatibilidad con Dojo (FALSE, por defecto).

  • addService($service): Añade un servicio al mapa. Puede ser un array de información para pasar al constructor de Zend_Json_Server_Smd_Service, o una instancia de esa clase.

  • addServices(array $services): Añade varios servicios a la vez.

  • setServices(array $services): Añade varios servicios a la vez, sobrescribiendo cualquier servicio previamente establecido.

  • getService($name): Obtiene un servicio por su nombre.

  • getServices(): Obtiene todos los servicios adjuntos.

  • removeService($name): Elimina un servicio del mapa.

  • toArray(): Convierte el mapa de servicio en un array.

  • toDojoArray(): Convierte el mapa de servicio en un array compatible con Dojo Toolkit.

  • toJson(): Convierte el mapa de servicio en una representación JSON.

Zend_Json_Server_Smd_Service tiene los siguientes métodos:

  • setOptions(array $options): Establece el estado del objeto a partir de un array. Cualquier mutador (métodos que comienzan con 'set') puede usarse como clave y establecerse mediante este método.

  • setName($name): Establece el nombre del servicio (típicamente, el nombre de la función o del método).

  • getName(): Recupera el nombre del servicio.

  • setTransport($transport): Establece el transporte del servicio (actualmente, solo se permiten los transportes admitidos por Zend_Json_Server_Smd).

  • getTransport(): Recupera el transporte actual.

  • setTarget($target): Establece el punto final URL del servicio (típicamente, será el mismo que el del SMD global al que está adjunto el servicio).

  • getTarget(): Obtiene el punto final URL del servicio.

  • setEnvelope($envelopeType): Establece la envoltura del servicio (actualmente, solo se permiten las envolturas admitidas por Zend_Json_Server_Smd).

  • getEnvelope(): Recupera el tipo de envoltura del servicio.

  • addParam($type, array $options = array(), $order = null): Añade un parámetro al servicio. Por defecto, solo es necesario el tipo de parámetro. Sin embargo, también puede especificar el orden, así como opciones tales como:

    • name: el nombre del parámetro

    • optional: si el parámetro es opcional o no

    • default: un valor por defecto para el parámetro

    • description: texto que describe el parámetro

  • addParams(array $params): Añade varios parámetros a la vez; cada parámetro debe ser un array asociativo que contenga como mínimo la clave 'type' que describa el tipo del parámetro, y opcionalmente la clave 'order'; cualquier otra clave se pasará como $options a addOption().

  • setParams(array $params): Establece muchos parámetros a la vez, sobrescribiendo cualquier parámetro existente.

  • getParams(): Recupera todos los parámetros actualmente establecidos.

  • setReturn($type): Establece el tipo del valor de retorno del servicio.

  • getReturn(): Obtiene el tipo del valor de retorno del servicio.

  • toArray(): Convierte el servicio en un array.

  • toJson(): Convierte el servicio en una representación JSON.