A camada de abstração de dados do Dojo, dojo.data, fornece uma API padrão aplicativos Dojo acessarem uma variedade de serviços de backend. O JsonRestStore, localizado na biblioteca DojoX de extensões do Dojo, permite-lhe rapidamente conectar seus aplicativos aos serviços Representational State Transfer (REST) de backend.
O JsonRestStore é uma boa solução para vincular o Dojo a serviços REST. Por padrão, porém, o JsonRestStore tem expectativas para as informações transmitidas e retornadas do serviço. O recurso Service Mapping Description (SMD) para personalizar essa interação é, na melhor hipótese, difícil de entender.
Quando os autores do aplicativo Dojo precisam se comunicar com um armazenamento de REST de backend preexistente, quando as comunicações do armazenamento não podem ser alteradas, então eles usam uma implementação dojox.rpc.Service customizada.
Neste artigo, aprenda sobre uma implementação de serviço genérica e simples para conectar serviços REST não padrão ao JsonRestStore. Explore como estendê-lo para seus próprios serviços através de um exemplo prático.
Para fazer o download do código de origem para este artigo, consulte a seção de Download
Implementação de serviço de exemplo
EasyRestService fornece implementações para quatro operações RES: POST (criar), GET (ler), PUT (atualizar) e DELETE (excluir). Para cada atividade, fornece a habilidade de conectar antes e depois de uma chamada do método do serviço. O ciclo de vida de chamada é:
- Construir uma estrutura de chamada Dojo XHR padrão contendo URL, argumentos e metadados de formato de dados.
- Chame os argumentos transformadores para o método. Esse método pode alterar a estrutura de chamada (incluindo o caminho) e ser usado para transformar a estrutura de chamada para se adequar às expectativas do serviço REST.
- Preencha o nó putData/postData/deleteData/getData da estrutura de chamada convertendo o nó de conteúdo para uma representação JSON.
- Chame o método XHR com a estrutura de chamada XHR alterada.
- Adicione um transformador de resultados para o retorno de chamada XHR. Esse método pode alterar a estrutura de dados dos resultados. Use=o para transformar os resultados na estrutura esperada por JsonRestStore.
A Listagem 1, mostra o código de exemplo.
Listagem 1. Origem do código de origem do EasyRestService
dojo.provide("com.ibm.developerworks.EasyRestService");
(function() {
var pa = com.ibm.developerworks.EasyRestService = function (path, serviceImpl, schema) {
// Enforce the dojox.rpc.Rest trailing slash functionality
path = path.match(/\/$/) ? path : (path + '/');
// A dojox.rpc.Service implementation is a function with 3 function members
var service;
// GET function
service = function(id, args) {
return _execXhr("get", id, args);
};
// POST function member
service['post'] = function(id, value) {
return _execXhr("post", id, value);
};
// PUT function member
service['put'] = function(id, value) {
return _execXhr("put", id, value);
};
// DELETE function member
service['delete'] = function(id) {
return _execXhr("delete", id);
};
// Generic XHR function for all methods
var _execXhr = function(method, id, content) {
// Transform the method string
var methodCapitalised = method.substring(0,1).toUpperCase()
+ method.substring(1).toLowerCase();
var methodUpperCase = method.toUpperCase();
var methodLowerCase = method.toLowerCase();
// Get the transformer functions
var argumentsTransformer = service["transform" + methodCapitalised + "Arguments"];
var resultTransformer = service["transform" + methodCapitalised + "Results"];
// Construct the standard query
var serviceArgs = {
url : path + (dojo.isObject(id) ? '?' + dojo.objectToQuery(id) :
(id == null ? "" : id)),
handleAs : "json",
contentType : "application/json",
sync : false,
headers : { Accept : "application/json,application/javascript" }
};
// Transform the arguments
// NOTE: argumentsTransformer has a reference to "service"
serviceArgs = argumentsTransformer(serviceArgs, arguments);
// Copy the content into the appropriate *Data arg
// getData, putData, postData, deleteData
// NOTE: If you want your arguments transformer to edit the *Data arg directly,
// move the arguments transformer invocation to after this call
serviceArgs[methodLowerCase + 'Data'] = content;
// Kick off the call
var xhrFunction = dojo['xhr' + methodCapitalised];
var deferred = xhrFunction(serviceArgs);
// Add our result transformer
// NOTE: resultTransformer has a reference to "service" too
deferred.addCallback(dojo.partial(resultTransformer, deferred));
return deferred;
};
// Mix in the service hooks
// Uses a "default" implementation that does nothing
// Service hooks will have a reference to the "service" object in their context
dojo.mixin(service,
new com.ibm.developerworks.EasyRestService.DefaultHooks(),
serviceImpl);
// Now remove any default _constructor() methods
// This is necessary as the JsonRestStore stack uses _constructor() differently
delete service['_constructor'];
// Remove the declaredClass member if it has been added
delete service['declaredClass'];
// Save the path away
service.servicePath = path;
// Save the schema
service._schema = schema;
return service;
};
})();
dojo.declare("com.ibm.developerworks.EasyRestService.DefaultHooks", null, {
transformGetArguments: function(serviceArgs) {
// Alter serviceArgs to provide the information the backend
// service requires
return serviceArgs;
},
transformPutArguments: function(serviceArgs) {
// Alter serviceArgs to provide the information the backend
// service requires
return serviceArgs;
},
transformPostArguments: function(serviceArgs) {
// Alter serviceArgs to provide the information the backend
// service requires
return serviceArgs;
},
transformDeleteArguments: function(serviceArgs) {
// Alter serviceArgs to provide the information the backend
// service requires
return serviceArgs;
},
transformGetResults: function(deferred, results) {
/*
* JsonRestStore expects the following format:
* [
* { id: "1", ... },
* { id: "2", ... },
* ...
* ]
*/
return results;
},
transformPutResults: function(deferred, results) {
/*
* JsonRestStore does not expect any specific content here
*/
return results;
},
transformPostResults: function(deferred, results) {
/*
* JsonRestStore expects:
* 1) A "Location" response header with location of the new item.
* From the Dojo API:
* The server’s response includes a Location header
* that indicates the id of the newly created object.
* This id will be used for subsequent PUT and DELETE
* requests. JsonRestStore also includes a
* Content-Location header that indicates the temporary
* randomly generated id used by client, and this
* location is used for subsequent PUT/DELETEs if no
* Location header is provided by the server or if
* a modification is sent prior to receiving a response
* from the server.
* NB: There is no JS method for altering response headers.
* You might wish to try overriding the
* deferred.ioArgs.xhr.getResponseHeader() method with your
* own implementation.
* 2) The new item in the following format:
* { id: "1", ... }
*/
return results;
},
transformDeleteResults: function(deferred, results) {
/*
* JsonRestStore does not expect any specific content here
*/
return results;
}
});
|
O código na Listagem 1 replica as funções padrão do dojox.rpc.Rest. Pode ser usado com JsonRestStore, como mostrado na Listagem 2.
Listagem 2. Uso padrão de
EasyRestService com JsonRestStore
dojo.require("com.ibm.developerworks.EasyRestService");
dojo.require("dojox.data.JsonRestStore");
var store = new dojox.data.JsonRestStore({
service: new com.ibm.developerworks.EasyRestService("https://mydomain.com/restservice"),
idAttribute : "id"
}); |
Por padrão, uma instância EasyRestService não altera os argumentos e resultados de nenhuma maneira. Em vez de alterar DefaultHooks para realizar os argumentos necessários e transformação de resultados, EasyRestService
fornece um mecanismo para substituir esses transformadores em uma base por instância.
EasyRestService fornece um mecanismo simples para o fornecimento de transformadores customizados. O exemplo na Listagem 3 altera o comportamento de EasyRestService para registrar a estrutura de chamada antes da execução.
Listagem 3. Customizando
EasyRestService
dojo.require("com.ibm.developerworks.EasyRestService");
var transformers = {
transformGetArguments: function(args) {
console.log(args);
return args;
}
};
var service = new com.ibm.developerworks.EasyRestService(
"https://mydomain.com/restservice", transformers);
|
Similarmente, todos os transformadores em DefaultHooks podem ser substituídos em uma base por instância.
Crie duas instâncias de EasyRestService: uma para um serviço conforme e outra para um serviço inconforme. O exemplo usa-as como os provedores de serviços para duas instâncias de JsonRestStore, e emite uma análise básica com relação ao armazenamento.
Na Listagem 4 e na Listagem 5, os serviços são simulados usando dois arquivos somente leitura contendo estruturas JSON.
Listagem 4. Serviço REST conforme, compliantService.json
[
{ id: 1, name: "Phil" },
{ id: 2, name: "John" }
] |
Listagem 5. Serviço REST inconforme, noncompliantService.json
{ items : [
{ id: 1, name: "Phil" },
{ id: 2, name: "John" }
] } |
Código de interação de serviço e armazenamento
JavaScript instanciará e consultará os armazenamentos usando o código na Listagem 6.
Listagem 6. Código JavaScript para interagir com os armazenamentos.
// Create a store using a service that needs no transformations
compliantStore = new dojox.data.JsonRestStore({
service : new com.ibm.developerworks.EasyRestService(
"./compliantService.json"),
idAttribute : "id"
});
// Cause an async fetch from the compliant service
dojo.create("p", {
innerHTML : "Requesting from compliant service"
}, dojo.body(), "last");
compliantStore.fetch({
onComplete : function(items, request) {
console.log(items);
// Log the number of items fetched
dojo.create("p", {
innerHTML : "Got " + items.length + " items from compliant service."
}, dojo.body(), "last");
}
});
// Create a store using a service which needs transformations
// to interpret the results
noncompliantStore = new dojox.data.JsonRestStore({
service : new com.ibm.developerworks.EasyRestService(
"./noncompliantService.json", {
transformGetResults : function(deferred, results) {
// This store wraps its results in an items object
// so return the items object
return results.items;
}
}),
idAttribute : "id"
});
// Cause an async fetch from the noncompliant service
dojo.create("p", {
innerHTML : "Requesting from noncompliant service"
}, dojo.body(), "last");
noncompliantStore.fetch({
onComplete : function(items, request) {
console.log(items);
// Log the number of items fetched
dojo.create("p", {
innerHTML : "Got " + items.length
+ " items from noncompliant service."
}, dojo.body(), "last");
}
}); |
Neste artigo, você aprendeu como conectar seus serviços REST ao JsonRestStore. Os exemplos mostraram um método simples de transformar sua interface de serviço para fornecer as assinaturas de que o JsonRestStore precisa. Para informações sobre a estrutura de dados completa esperada pelo JsonRestStore, consulte os comentários em DefaultHooks, a documentação do JsonRestStore em DojoCampus, e a documentação da API.
Para informações sobre a estrutura de dados completa esperada pelo JsonRestStore, consulte os Recursos .
| Descrição | Nome | Tamanho | Método de download |
|---|---|---|---|
| EasyRestService code sample - project archive | EasyRestServiceExample.zip | 6.5KB | HTTP |
Informações sobre métodos de download
Aprender
- Leia a documentação do DojoCampus para o JsonRestStore.
- Explore a API Dojo para o JsonRestStore. JsonRestStore faz todas as modificações salvas serem enviadas ao servidor usando comandos REST (GET, PUT, POST ou DELETE).
Obter produtos e tecnologias
- Faça o download das versões de avaliação de produto IBM ou o explore as versões de teste on-line no IBM SOA Sandbox e coloque suas mãos em ferramentas de desenvolvimento de aplicativos e produto de middleware de DB2®, Lotus®, Rational®, Tivoli®, e WebSphere®.
Discutir
- Crie seu perfil do My developerWorks hoje e configure uma lista de acompanhamento sobre Dojo e REST. Conecte-se e fique conectado com o My developerWorks.
- Encontre outros membros do developerWorks interessados no desenvolvimento da Web.
- Compartilhe seus conhecimentos: ingresse em um dos grupos do developerWorks enfocados nos tópicos da Web.
- Roland Barcia fala sobre Web 2.0 e middleware nesse blog.
- Siga indicadores compartilhados sobre os tópicos da Web dos membros do developerWorks.
- Obtenha respostas rapidamente: Visite o fórum Web 2.0 Apps.
Nick Maynard trabalha para a equipe IBM Software Solutions Transformation em Hursley, Reino Unido. Ele especializou-se ou programação da Web, Linux, serviços da Web e tecnologias de integração de negócios. É possível entrar em contato com Nick pelo nick.maynard@uk.ibm.com.