Web Services

De artista.frustrado

OBS: este documento ainda está em constante atualização

Tabela de conteúdo

Definição

Segundo a definição da W3C um Web Service é um sistema de software projetado para suportar interoperabilidade máquina-para-máquina através de uma rede. Frequentemente são API's Web que podem ser acessadas via uma rede, como a Internet, e executadas em um sistemas remoto que hospeda os serviços requisitados.

Funcionamento

Na programação tradicional o programa roda todo no computador do usuário, acesando bibliotecas e recursos locais.

programa local

Em um sistema baseado em consumo de Web Service o programa roda até o momento em que tem que buscar algum recurso no servidor, faz a requisição, recebe a resposta e continua o processamento.

web services simplificado

É claro que para que essa divisão de trabalho seja efetivada novas camadas devem ser adicionadas ao programa, o que a princípio aumenta a complexidade do programa como um todo. O programa cliente chama o recurso no servidor fazendo a requisição a um proxy (agente que trabalha como intermediário entre o servidor e o cliente, ocultando toda a complexidade das operações), o qual serializa a requisição e a repassa ao servidor via o protocolo HTTP. O servidor chama as rotinas requisitadas e retorna os dados serializados, via HTTP também. O cliente recebe os dados do proxy, já desserializados e continua o processamento.

web services elaborado

Proxy, em inglês, refere-se a algo ou alguém que atua em nome de outra pessoa. Em computação é um agente (interface ou serviço) que que repassa as requisições para outro agente.

Mas na prática, como isso funciona? Vamos ver um exemplo simples:

Exemplo de programa local

Abaixo vemos o código, em python de uma simulação uma calculadora com as 4 operações básicas:

#!/usr/bin/env python
 
def soma(valor1, valor2):
        return valor1 + valor2
 
def subtracao(valor1, valor2):
        return valor1 - valor2
 
def multiplicacao(valor1, valor2):
        return valor1 * valor2
 
def divisao(valor1, valor2):
        return valor1 / valor2
 
 
if __name__ == '__main__':
        print soma(4, 5)
        print subtracao(5, 3)
        print multiplicacao(4, 5)
        print divisao(10, 5)

Tudo é executado no computador do usuário.

Exemplo básico utilizando python e XML-RPC

Abaixo temos o mesmo programa como um WebService utilizando XML-RPC. Preste atenção em na importação da biblioteca xmlrpclib a qual encapsula todos os procedimentos necessários para requisitar o processamento no servidor repassando e recebendo os dados do resto do programa.

No servidor instância da classe SimpleXMLRPCServer necessita que as funções sejam registradas para que possam ser expostas para o cliente.

Servidor:

#!/usr/bin/env python
 
import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer
 
def soma(valor1, valor2):
        return valor1 + valor2
 
def subtracao(valor1, valor2):
        return valor1 - valor2
 
def multiplicacao(valor1, valor2):
        return valor1 * valor2
 
def divisao(valor1, valor2):
        return valor1 / valor2
 
 
server = SimpleXMLRPCServer(("localhost", 8000))
 
print "Listening on port 8000..."
server.register_function(soma, "soma")
server.register_function(subtracao, "subtracao")
server.register_function(multiplicacao, "multiplicacao")
server.register_function(divisao, "divisao")
 
server.serve_forever()

Cliente:

#!/usr/bin/env python
 
import xmlrpclib
 
proxy = xmlrpclib.ServerProxy("http://localhost:8000/")
print str(proxy.soma(100, 100)
print str(proxy.subtracao(100, 100)
print str(proxy.multiplicacao(100, 100)
print str(proxy.divisao(100, 100)

Agora nós temos um sistema baseado em arquitetura cliente/servidor. Para isso adicionamos mais um elemento na chamada das funções, um proxy.

Exemplo básico utilizando python e SOAP

Servidor:

#!/usr/bin/env python
 
import SOAPpy
 
def soma(valor1, valor2):
        return valor1 + valor2
 
def subtracao(valor1, valor2):
        return valor1 - valor2
 
def multiplicacao(valor1, valor2):
        return valor1 * valor2
 
def divisao(valor1, valor2):
        return valor1 / valor2
 
server = SOAP.SOAPServer(("localhost", 8080))
server.registerFunction(soma)
server.registerFunction(subtracao)
server.registerFunction(multiplicacao)
server.registerFunction(divisao)
server.serve_forever()

Cliente:

#!/usr/bin/env python
 
import SOAPpy
proxy = SOAPpy.SOAPProxy("http://localhost:8080/")
 
print str(proxy.soma(100, 100)
print str(proxy.subtracao(100, 100)
print str(proxy.multiplicacao(100, 100)
print str(proxy.divisao(100, 100)

Exemplo basico utilizando C# e mono

Servidor:

Crie um arquivo chamado Matematica.asmx com o codigo abaixo:

<%@ WebService Language="C#" Class="Matematica.Matematica" %>
 
using System;
using System.Web.Services;
 
namespace Matematica
{
	[WebService (Namespace = "http://artista.frustrado.com.br.org/Matematica")]
	public class Matematica : WebService
	{
		[WebMethod]
		public int soma (int number1, int number2)
		{
			return number1 + number2;
		}
 
		[WebMethod]
		public int subtracao (int number1, int number2)
		{
			return number1 - number2;
		}
 
		[WebMethod]
		public int multiplicacao (int number1, int number2)
		{
			return number1 * number2;
		}
 
		[WebMethod]
		public int divisao (int number1, int number2)
		{
			return number1 / number2;
		}
	}
}

Abra um console e entre na pasta em que colocou o arquivo e rode o servidor http do mono, o xsp. No exemplo abaixo iremos utilizar o xsp2, versao do xsp do mono2.

xsp

Agora abra um navegador, como o Mozilla Firefox por exemplo, e acesse o endereço http://localhost:8080/Matematica.asmx e voce podera navegar atraves da descricao do servico assim como visualizar o WSDL do mesmo.

Como C# e uma linguagem estaticamente tipada torna-se necessario recriar os objetos que iremos acessar no servidor construindo uma proxy. Para tanto iremos utilizar a ferramenta wsdl

wsdl2 "http://localhost:8080/Matematica.asmx?wsdl=0"

Ira importar a descricao do servico e gerar o codigo de proxy, a classe Matematica como definida no servidor.

using System;
 
namespace Matematica
{
 
 
	public class Cliente
	{
 
		public static void Main( string[] args )
		{
			Matematica cliente = new Matematica();
			Console.WriteLine(cliente.soma(100, 100));
			Console.WriteLine(cliente.subtracao(100, 100));
			Console.WriteLine(cliente.multiplicacao(100, 100));
			Console.WriteLine(cliente.divisao(100, 100));
		}
	}
}

E para compilar execute:

gmcs2 Matematica.cs -r:System.Web.Services Cliente.cs

Exemplos Práticos

Cadastrar imagens no picasaweb

Faça o download e instale a biblioteca gdata

Caso esteja utilizando linux:

wget http://gdata-python-client.googlecode.com/files/gdata.py-1.2.4.zip
unzip gdata.py-1.2.4.zip
cd gdata.py-1.2.4
python setup.py intall

Exemplo de cliente que lista os seus albuns:

#!/usr/bin/env python
 
import gdata.photos.service
import gdata.media
import gdata.geo
 
username = "seulogin"
password = "suasenha" 
 
gd_client = gdata.photos.service.PhotosService()
gd_client.email = "%s@gmail.com" % username
gd_client.password = password 
gd_client.source = 'tutorial_frustrado_01'
gd_client.ProgrammaticLogin()
 
albums = gd_client.GetUserFeed(user="seu-login")
for album in albums.entry:
       print 'title: %s, number of photos: %s, id: %s' % (album.title.text, album.numphotos.text, album.gphoto_id.text)

Exemplo de cliente que cria um album e publica todas as imagens de seu desktop:

#!/usr/bin/env python
 
import gdata.photos.service
import gdata.media
import gdata.geo
import os, re
 
username = "seulogin"
password = "suasenha" 
 
caminhoOrigem = "%/Desktop" % os.environ['HOME']
 
gd_client = gdata.photos.service.PhotosService()
gd_client.email = "%s@gmail.com" % username
gd_client.password = password 
gd_client.source = 'tutorial_frustrado_01'
gd_client.ProgrammaticLogin()
 
album = gd_client.InsertAlbum(title='TutorialFrustrado', summary='Album criado pelo tutorial frustrado')
album_url = '/data/feed/api/user/%s/albumid/%s' % (username, album.gphoto_id.text)
 
files = os.listdir(caminhoOrigem)
test = re.compile("\.(jpg|jpeg)$", re.IGNORECASE)
files = filter(test.search, files)
 
for file in files:
       photo = gd_client.InsertPhotoSimple(album_url, file, 'Uploaded using the API', "%s/%s" % (caminhoOrigem, file), content_type='image/jpeg')
 
photos = gd_client.GetFeed('/data/feed/api/user/%s/albumid/%s?kind=photo' % (username, album.gphoto_id.text))
for photo in photos.entry:
       print 'Photo title:', photo.title.text

Links