Web Services
Introducció
Un servei web o web service ve a ser un servei més del sistema informàtic (o sigui, un sistema d'intercanvi d'informació), però amb algunes peculiaritats:
- Utilitza el protocol HTTP per intercanviar les dades.
- Utilitza els mètodes HTTP: GET, POST, PUT, DELETE (inspirat en el CRUD de les BBDD).
 - Pot tenir altres mètodes (arbitraris) però no és tan usual.
 
 - Sol aplicar-se a sistemes navegables (enllaços/hipervincles).
 - Sol estar al port 80
 - Sol utiltizar una arquitectura REST o REpresentational State Transfer.
- Arquitectura client-servidor
 - Sense estat
 - Cachejable
 - Per capes
 - Codi "on demand": compartit (al client, p.ex. javascript)
 - Interfície uniforme
 
 
Avantatges:
- Estandarització
 - ...
 
Exemple en Python i CherryPy
En Python solem utiltizar la llibreria json o bé simplejson.
Els mètodes més importants son:
- json.loads
 - json.dumps
 
En moltes ocasions, els propis "renderers" del nostre framework ens faran aquesta feina, tot i que estan utilitzant aquesta llibreria.
# http://www.cherrypy.org/
# http://docs.cherrypy.org/en/latest/tutorial/REST.html
import cherrypy, json
class Xat:
    exposed = True
    
    # llistar missatges
    def GET(self,*args,**kwargs):
        # processem parametres
        canal = kwargs.get("canal")
        # preparem resposta
        resposta = {}
        resposta["status"] = False
        resposta["missatge"] = "Servei no implementat (encara). Canal=" + str(canal)
        return json.dumps( resposta )
        
    # enviar missatges
    @cherrypy.tools.json_in()
    def POST(self,*args,**kwargs):
        dades = cherrypy.request.json
        # "dades" conte elements JSON deserialitzats amb dicts, llista, etc.
        resposta = {}
        resposta["status"] = True
        resposta["missatge"] = "Missatge llegit correctament: " + str(dades)
        return json.dumps( resposta )
if __name__ == '__main__':
    cherrypy.tree.mount(
        Xat(), '/api/xat',
        {'/':
            {'request.dispatch': cherrypy.dispatch.MethodDispatcher()}
        }
    )
    cherrypy.engine.start()
    cherrypy.engine.block()
Utilitza la següent crida cURL per testejar:
$ curl http://localhost:8080/api/xat -d '"hola"' -H "Content-Type: application/json" -X POST
El -X POST és opcional ja que sempre que li posem un "-d" (dades) ja s'assumeix que és POST.
Fixeu-vos en què:
- Les dades d'entrada ens les parseja el framework: 
dades = cherrypy.request.json
 - Les dades de sortida les hem de transformar a JSON 
return json.dumps
- El framwork s'encarrega de posar headers.
 
 
Exemple en Python i Pyramid
Fixa't en què en aquest cas:
- El framwork ja ens parseja l'entrada:
dades = request.json_body
- O sigui, no cal fer un json.loads
 
 - També el propi framwork ens parseja la sortida, fent un return d'un diccionari Python que es tradueix automàticament a JSON.
- El punt clau per realitzar això és el renderer:
@view_config(route_name='xat_set_missatge_ws', renderer='jsonp')
 
 - El punt clau per realitzar això és el renderer:
 
@view_config(route_name='xat_set_missatge_ws', renderer='jsonp')
def xat_set_missatge_ws(request):
    try:
        # ho intentem per GET (JSONP)
        remitent = request.GET.get("remitent")
        missatge = request.GET.get("missatge")
        if remitent and missatge:
            if remitent.strip() and missatge.strip():
                linia = remitent + "\t" + missatge 
        else:
            # ho intentm per POST (JSON)
            dades = request.json_body
            linia = dades["remitent"] + "\t" + dades["missatge"] 
        if "<" in linia or "\n" in linia:
            return {
                "servei":"xat",
                "canal":"principal",
                "status":False,
                "missatge":"ERROR: caracters ilegals"
            }
        file = open(STORAGE_FILENAME,"a+")
        file.write(linia+"\n");
        file.close()
            
    except ValueError:
        return {"servei":"xat",
		"canal":"principal",
		"status":False,
		"missatge":"ERROR: JSON incorrecte"
        }
    except Exception as e:
        print type(e).__name__
        print e.args
        return {"servei":"xat",
		"canal":"principal",
		"status":False,
		"missatge":"ERROR desonegut: " + type(e).__name__
        }
    
    return {	"servei":"xat",
		"canal":"principal",
		"status":True,
		"missatge":"missatge enregistrat correctament"
    }