BatPlone e WebService: Uma dupla dinâmica Plone Symposium South America Brasília 2012
O que vamos abordar? - O que são e para que servem os WebServices? - Vantagens e Desvantagens - WebService SOAP vs Rest - Exemplos de Integração - Dicas de Otimização - Conclusões
O que são e para que servem os WebServices? WebService é uma solução utilizada na INTEGRAÇÃO de sistemas e na comunicação entre APLICAÇÕES DIFERENTES. Os WebServices são COMPONENTES que permitem às aplicações enviar e receber dados em formato XML(!). Cada aplicação pode ter a sua própria "linguagem", que é traduzida para uma linguagem universal, o formato XML(!). Aplicação A (Portal Plone) XML WebService Aplicação B (Sistema Legislativo em Java)
Vantagens e Desvantagens Vantagens - Permite a integração entre aplicação escritas em linguagens diferentes - Permite a integração de aplicações dispersas geograficamente (Internet) - Isolamento em camadas (negócio e apresentação) - Inteligível e intuitiva para o ser humano, o que facilita o desenvolvimento de novos aplicativos Desvantagens - Adiciona complexidade as aplicações - Segurança - Pode comprometer a performance da aplicação consumidora - Tipicamente o tamanho do pacote é muito superior aos dados efetivamente úteis
WebServices SOAP vs Rest SOAP Simple(?) Object Access Protocol Rest Representational State Transfer - Mais complexo, lento e pesado - Mais simples, rápido e leve - Mais Seguro (pacote fechado ) - Menos seguro (mais pode usar SSL/HTTPS) - Melhor para operações que precisam ser continuadas (Stateful) - Resultado XML, formatado por um WSDL - Melhor para operações isoladas (Stateless) - Pode ter qualquer formato, inclusive XML e JSON - Permite definição de tipos de dados - Todos os dados são do tipo STRING - Dificuldade para testar e fazer cache em Proxys HTTP - Facilidade para testar e fazer cache em Proxys HTTP - Tamanho do pacote de dados maior - Tamanho do pacote de dados menor
Exemplos de Integração - Google, Yahoo, Amazon, ebay, Buscapé - Câmara dos Deputados (Dados Abertos) package br.gov.camara; import javax.ws.rs.get; import javax.ws.rs.path; from bottle import route, run @route('/hello/:name') def index(name='world'): return '<b>hello %s!</b>' % name run(host='localhost', port=8080) @Path("/hello") public class Hello { @GET @Produces(MediaType.TEXT_PLAIN) public String sayplaintexthello() { return "Hello"; } @GET @Produces(MediaType.TEXT_XML) public String sayxmlhello() { return "<?xml version=\"1.0\"?>" + "<hello> Hello" + "</hello>"; } } @GET @Produces(MediaType.TEXT_HTML) public String sayhtmlhello() { return "<html> " + "<title>" + "Hello Jersey" + "</title>" + "<body><h1>" + "Hello" + "</body></h1>" + "</html> "; }
Exemplos de Integração # -*- coding: utf-8 -*- import SOAPpy from SOAPpy import SOAPProxy TIMEOUT = 60 class Webservices(BrowserView): def webservice_caller(self, wsdl, metodo, parametros, timeout = TIMEOUT, map = {}): if isinstance(parametros, dict) and parametros.get('timeout', None) is not None: timeout = parametros['timeout'] SOAPpy.Config.methodAttributeParameters = map p = SOAPpy.WSDL.Proxy(wsdl, timeout = timeout) if isinstance(parametros, dict): ret = getattr(p, metodo)(**parametros) else: if not isinstance(parametros, tuple): parametros = (parametros,) ret = getattr(p, metodo)(*parametros) return ret
Exemplos de Integração # -*- coding: utf-8 -*- from restful_lib import Connection import simplejson, urllib class Webservices(BrowserView): def restful_caller(self, url, metodo, parametros, http_metodo): try: conn = Connection(url) except: return 'Erro na conexão com ' + url ret = None if http_metodo.upper() == 'GET': try: headers = {'Content-type': 'text/xml', 'Accept':'text/xml'} ret = conn.request_get(resource = metodo, args = parametros, headers) except: ret = 'ERRO na chamada metodo ' + metodo return ret def wsrestful_json_caller(self, url, parametros): url = url + '?' + urllib.urlencode(parametros) result = simplejson.load(urllib.urlopen(url)) return result
Exemplos de Integração #@viewcache(timeout=900) //@memoize def ws_obtemlistadeputados(self): dados = [] parms=() try: dados = self.webservice_caller(wsdl=self.url_wsdl, metodo='obtemdeputados', parametros=parms) except Exception, ex: pass return dados parms=(primeiraletra,codlotacao) webservices = context.restrictedtraverse('@@view_camara_webservice') wsdl = getattr(context,'webserviceserver')+'?wsdl' metodo='listadeputados' o = webservices.webservice_caller(wsdl,metodo,parametros=parms, timeout=60) return o ws = context.restrictedtraverse('@@view_camara_webservice') return ws.wsrestful_json_caller(url, cidade=goiania )
Dicas de Utilização - Uso de Cache em diferentes níveis > Proxy > Zope (@memoize) > MemCached (@viewcache) - WebServices otimizados e que tragam apenas as informações pertinentes - Usuários de BD com permissões restritas - Ajustar o timeout ou usar de forma Assincrona
Conclusões - Se utilizada da forma correta é uma solução eficaz - Avaliar sempre se não seria possível uma abordagem mais direta (Ex: SqlAlchemy) - Sempre que possível, utilizar REST
Obrigado Fábio Surrage de Medeiros fabio.medeiros@camara.gov.br Rafahela Bazzanella, Clayton Caetano, Wilton Alencar