JsonXat

De Cacauet Wiki
Dreceres ràpides: navegació, cerca

Realitzarem una aplicació de xat a través del mòbil i de la web.

Per permetre una màxima eficiencia i bon disseny utilitzarem serveis web. Et caldrà haver llegit els següents articles:


Introducció

Objectius:

  • Treballar web services.
  • Treballar JSON com a format estàndard de comunicació.
  • Establir una API de referència independent de l'implementació.
  • Treballar aplicacions mòbils.

Recursos:

  • Links articles anteriors.
  • curl: (Call URL) utilitat per línia de comandes Unix per testejar serveis web (i d'altres).
  • Pàgina web de test i exemple amb JavaScript:


Passes recomanades

  1. Costat servidor: serveis web
  2. Costat client: exemple JavaScript
  3. Aplicació mòbil:


Definint la nostra API dels serveis JSON

Aquesta part és important. Si estem fent un projecte que requereix comunicació entre diversos mòduls caldrà que realitzem un document com aquesta secció, indicant:

  1. quins serveis oferim
  2. com s'han de demanar (valors d'entrada)
  3. què ens retornen

Necessitem una interfície per parlar amb el servidor. Ens permetrà definir el protocol per enviar i rebre missatges independentment de la implementació que tinguem al servidor. És a dir que podem tenir el servei muntat sobre el filesystem o sobre una base de dades i que el client no noti la diferència, ja que la interfície és comuna.

Bàsicament volem enviar i rebre missatges. El nostre protocol tindrà, doncs:

  • Demanar llista de canals: xat_get_canals_ws. Prova amb:
    $ curl http://enricus.tk/serveis/xat_get_canals_ws
  • Demanar missatges per un canal: xat_get_canal_ws/<canal>
  • Enviar missatge per un canal: xat_set_missatge_ws

Detalls a continuació...

xat_get_canal_ws

xat_get_canal_ws (entrada)
atribut valor (exemple) comentari
canal principal canal de xat del què volem rebre els missatges


xat_get_canal_ws (sortida)
atribut valor comentari
status true/false ens informa si tot ha anat bé
missatges [ {"remitent":"pere","missatge":"hola!"} , {} , {} ] llista de missatges del canal
missatge "canal inexistent"
"error intern"
detalls del status de la comanda

Test (versió JSON amb POST):

$ curl http://enricus.tk/serveis/xat_get_canal_ws -d '{"canal":"principal"}'

Test (simulant JSONP amb GET):

$ curl http://enricus.tk/serveis/xat_get_canal_ws?canal=principal

Prova d'introduir-hi errors per veure el resultat que ens ofereix.

xat_set_missatge_ws

xat_set_missatge_ws (entrada)
atribut valor (exemple) comentari
canal principal canal de xat al què volem enviar el missatge
missatge "hola, com anem per aquí?" cos dels missatge a enviar


Cal tenir en compte que potser no us cal tota la informació que el servei ens dóna:

xat_set_missatge_ws (sortida)
atribut valor comentari
servei "xat" nom del servei que estem utilitzant (sempre serà "xat")
canal "principal" canal de xat al què hem volgut enviar el missatge
status true/false si la petició s'ha resolt OK (gravar missatge)
missatge "ERROR: JSON incorrecte"
"missatge enregistrat correctament"
missatge amb detalls de l'execució

Tingueu en compte que les dades es poden enviar per GET (cas del JSONP) o per POST (JSON normal). El servei implementa els dos casos, però si ho feu vosaltres penseu en què us cal comprovar les dades de les 2 fonts (GET i JSON).

Podeu testejar el POST amb: (prova també de variar la clau remitent o missatge per provocar que et retorni error)

$ curl http://enricus.tk/serveis/xat_set_missatge_ws -d '{"remitent":"nuria","missatge":"prova aviam"}'

Per testejar el GET amb JSONP utilitzeu la web: (provoca error si canvies el canal per un d'inexistent)

http://enricus.tk/jsonxat.html


Directiva de seguretat de browsers i JSONP

En aquesta pràctica ens convé utiltizar JSONP (wikipedia) enlloc del JSON habitual per solventar un "problema" de seguretat. Bé, no és un problema, sinó una directiva amb molt de sentit:

SOP o Same-Origin Policy: simplement, els navegadors o browsers impedeixen crides a serveis en servidors que no son el què apareix a la URL en curs.

És lògic i convenient, perquè si no, ens poden "robar la cartera" quan naveguem.

Pel desenvolupament, però, ens provocarà certes molèsties. Les alternatives son:

  • Treballem sempre amb el mateix servidor+port amb JSON (important el port, diferents ports el navegador els considera diferents sites).
  • Col·locar un proxy en el nostre servidor perquè ens redirigeixi certes crides al 2n servidor (apache2 mod_proxy).
  • Utiltizar un "truc" anomenat JSONP. Ens permetrà cridar serveis en un altre servidor però només ens funciona a través de GET.

Teniu un exemple de tot plegat (particularment de la part JavaScript) a:

http://enricus.tk/jsonxat.html

Cal implementar JSONP al servidor i al client. La part negativa de tot plegat és que si després volem fer els serveis amb JSON haurem de duplicar codi o bé passar-lo de JSONP a JSON (seria convenient per seguretat).


App mòbil Android

Utilitzeu l'article Android per iniciar-vos amb les aplicacions pel SO de Google.

Volem realitzar una app que ens faci la mateixa funció que la web d'exemple anterior. És a dir, que carregui i envii missatges a un servidor seguint el protocol marcat per la nostra API.

Exemples de tractament de dades JSON amb Android:


Procediment recomanat:

  1. Utilitzar llibreria estàndard de HTTP per descarregar-nos el "string" del servidor.
    • Us trobareu que el main thread no permet executar requests HTTP i llança l'excepció NetworkOnMainThreadException. Això ho fa per evitar que el main thread es quedi "penjat" esperant alguna cosa d'internet.
      Solució: utilitzar un thread apart.
      Threads en Java. Feu els exercicis de threads abans de continuar.
  2. Mostrar el string a un textView.
    • S'ha de fer des del GUI (main) thread. Per tant el nou thread que hem creat no pot fer un simple setText. Llegiu la resposta aquí (utiltizar view.post):
      http://stackoverflow.com/questions/9884246/how-to-set-text-of-text-view-in-another-thread
    • Ull quan actualitzeu una View (com el TextView). Perquè s'actualitzi (equival a un REPAINT de Qt):
      • Utilitzeu .invalidate() si esteu al main thread.
      • Utiltizeu .postInvalidate() si esteu a qualsevol altre thread.
  3. "Parsejar" el string obtingut i descodificar les dades dins d'estructures del nostre llenguatge (arrays, diccionaris, etc.). Utilitzar JSONObject
  4. Enviar missatges al xat a través del web service xat_set_missatge_ws