Vergangene Woche habe ich erläutert, wie Sie eine Web-API mit Windows Azure, ASP.Net und C# erstellen können.
Diese Woche verbinden wir das Ganze mit unserer ursprünglichen Pi Passport Klassifizierung. Da unser System in verschiedene Ebenen unterteilt ist, sollten wir hier eigentlich nur die Datenebene anpassen müssen.
An dieser Stelle nochmal zur Erinnerung – so sah unser Projekt vor zwei Wochen aus:
Hier läuft quasi alles über zwei xml-Dateien, von denen eine Datei alle Daten zu unseren Aktivitäten und die andere Daten zur Person enthält.
Jetzt, da wir eine Web-API haben, werden Personen im Internet und Aktivitätenbeschreibungen dort oben gespeichert. Fragen und Antworten zu Aktivitäten kommen jedoch direkt auf den Pi, da wir den Interwebs nicht unbedingt entnehmen müssen, wie ein Benutzer eine Aktivität erreicht hat – wichtig ist nur, dass wir wissen, DASS er sie erreicht hat. Ein paar Hintergrundinformationen zur Aktivität sind an dieser Stelle ebenfalls hilfreich. Allerdings kann es passieren, dass das Ganze dadurch ein wenig unübersichtlich wird. Es ist wichtig, dass die IDs mit dem Server übereinstimmen, da am Ende sonst die Aktivitäten-IDs auf dem Pi von denen, die auf dem Server angegeben sind, abweichen.
Deshalb müssen wir hier Folgendes beachten:
- Ändern Sie Speichern/Laden von Personen, um Requests ausführen zu können.
- Ändern Sie Speichern/Laden von Aktivitäten, um Requests ausführen zu können und achten Sie darauf, dass die IDs zueinander passen.
- Ändern Sie die Parameter der Klassifizierung so, dass die URLs, die wir aufrufen müssen, zu den APIs passen.
- Passen Sie die Read-/Admin-Dateien so an, dass die Parameter zur Erstellung der Klassifizierung stimmen.
Lassen Sie uns mit dem LoadPi anfangen:
- def LoadPi(self):
- dom=self.Load(self.pi,"piSyst")
- try:
- pi_tag=dom.getElementsByTagName("pi")[0]
- except:
- self.SavePi()
- dom=self.Load(self.pi,"piSyst")
- pi_tag=dom.getElementsByTagName("pi")[0]
- a_q=requests.get(self.pi_url)
- a_data=a_q.json()
- a_dict={}
- for a in a_data:
- a_dict[a["ID"]]={"Description":a["Description"]}
- pid=pi_tag.getAttribute("ID")
- a_tags=pi_tag.getElementsByTagName("achievement")
- achievements={}
- if int(pid) in a_dict.keys():
- achievements[pid]={"question":None,"answers":None,"Description":a_dict[int(pid)]["Description"]}
- else:
- desc=raw_input("Please enter a description for this pi:")
- post=requests.post(self.pi_url,data=json.dumps({"Description":desc}),headers={"Content-type":"application/json"})
- id=str(int(post.json()["ID"])-1)
- achievements[id]={"question":None,"answers":None,"Description":desc}
- pi_tag.setAttribute("ID",str(id))
- file=open(self.pi,'w')
- dom.writexml(file)
- a_q=requests.get(self.pi_url)
- a_data=a_q.json()
- a_dict={}
- for a in a_data:
- a_dict[a["ID"]]={"Description":a["Description"]}
- for a in a_tags:
- id=a.getAttribute("ID")
- qtag=a.getElementsByTagName("question")[0]
- question=qtag.childNodes[0].data
- atag=a.getElementsByTagName("answer")
- answers=[]
- for an in atag:
- answers.append(an.childNodes[0].data)
- achievements[id]={"question":question,"answers":answers,"Description":a_dict[id]["Description"]}
- return achievements
An dieser Stelle müssen Sie Requests installieren. Das ist so ähnlich wie urllib, aber wesentlich einfacher zu verstehen. Über diesen Befehl finden Sie sie auf PyPip:
sudo pip install requests
Wir arbeiten uns hier Schritt für Schritt durch:
- dom=self.Load(self.pi,"piSyst")
- try:
- pi_tag=dom.getElementsByTagName("pi")[0]
- except:
- self.SavePi()
- dom=self.Load(self.pi,"piSyst")
- pi_tag=dom.getElementsByTagName("pi")[0]
- a_q=requests.get(self.pi_url)
- a_data=a_q.json()
- a_dict={}
- for a in a_data:
- a_dict[a["ID"]]={"Description":a["Description"]}
- pid=pi_tag.getAttribute("ID")
- a_tags=pi_tag.getElementsByTagName("achievement")
- achievements={}
- if int(pid) in a_dict.keys():
- achievements[pid]={"question":None,"answers":None,"Description":a_dict[int(pid)]["Description"]}
In diesem ersten Abschnitt passiert Folgendes:
• Die dom wird geladen und das Pi Tag gesucht.
• Falls nicht vorhanden, wird das Pi gespeichert und das dom Tag erstellt, damit es beim nächsten Mal bereitsteht.
• Es wird ein Request an die entsprechende API geschickt, alle Aktivitäten aufzulisten.
• Das JSON-Objekt wird in ein Python-Verzeichnis geladen.
• Die Pi Aktivität auf dem Server wird überprüft und eine Instanz mit den Deets dieser Aktivität erstellt.
- else:
- desc=raw_input("Please enter a description for this pi:")
- post=requests.post(self.pi_url,data=json.dumps({"Description":desc}),headers={"Content-type":"application/json"})
- id=str(int(post.json()["ID"])-1)
- achievements[id]={"question":None,"answers":None,"Description":desc}
- pi_tag.setAttribute("ID",str(id))
- file=open(self.pi,'w')
- dom.writexml(file)
- a_q=requests.get(self.pi_url)
- a_data=a_q.json()
- a_dict={}
- for a in a_data:
- a_dict[a["ID"]]={"Description":a["Description"]}
- for a in a_tags:
- id=a.getAttribute("ID")
- qtag=a.getElementsByTagName("question")[0]
- question=qtag.childNodes[0].data
- atag=a.getElementsByTagName("answer")
- answers=[]
- for an in atag:
- answers.append(an.childNodes[0].data)
- achievements[id]={"question":question,"answers":answers,"Description":a_dict[id]["Description"]}
- return achievements
Weiter geht es mit diesem Abschnitt:
• Hier wird festgestellt, dass das Pi Tag nicht in den Serveraktivitäten gelistet ist.
• Sie werden aufgefordert, ein solches Tag zu erstellen, indem Sie der Aktivität eine Beschreibung hinzufügen. Diese wird dann mittels eines Post-Requests an den Server weitergeleitet.
• Um sicherzustellen, dass auch alles zueinander passt, wird die ID vom Server sowohl in das Aktivitätenverzeichnis als auch in die pi.xml-Datei übernommen.
• Jetzt fragt das System Sie nach einer Liste der Aktivitäten und erstellt daraus ein Verzeichnis.
• Anschließend geht es in die xml-Datei, aus der es alle lokalen Aktivitäten zieht. Die dazugehörigen Beschreibungen werden der Serveraktivitäten-Liste entnommen.
Lassen Sie uns noch den Initialisierer für die Klassifizierung ändern, bevor wir es vergessen:
- def __init__(self,pifile,people_url,pi_url,link_url):
- self.pi=pifile
- self.pi_url=pi_url
- self.people_api=people_url
- self.link_api=link_url
- self.achievements=self.LoadPi()
- self.people=self.LoadPeople()
Hier haben wir immer noch die Pi Datei – das ist eine xml thingymagig, die alle Daten zu jeder Aktivitätenfrage enthält. Allerdings haben wir auch noch drei API-Links: einen für Aktivitäten (pi_url), einen für Personen (people_api) und einen für Links (link_api).
Jetzt gehen wir zurück auf SavePi:
Die Vorgehensweise ist wieder ähnlich – wir speichern alle Aktivitäten in der Pi Datei und prüfen, ob sie auch auf dem Server vorkommen. Das tun wir, indem wir alle Aktivitäten auf den Server laden und prüfen, ob sie auch wirklich im Aktivitätenverzeichnis auftauchen. Wenn sie zwar auf dem Server, jedoch nicht im Verzeichnis gelistet werden, dann löschen Sie sie vom Server. Wenn es andersherum ist, dann erstellen Sie einen Eintrag auf dem Server.
Nun geht es weiter mit SavePeople:
Anstatt eine xml-Datei zu verwenden, machen wir jetzt Folgendes:
• Stellen Sie eine Verbindung mit der API für Personen her.
• Laden Sie alle hoch.
• Verbinden Sie sie mit der API für Links.
• Laden Sie alle Aktivitäten für die Personen, die wir gerade hochgeladen haben.
• Vergleichen Sie die aktuelle Personenliste mit dieser Liste.
• Wenn einige Personen nicht auf der Serverliste auftauchen, fügen Sie sie beiden APIs mittels Post-Requests hinzu.
Vielleicht fragen Sie sich, warum wir nicht prüfen, ob die Personen auch auf der Serverliste stehen: Wir vergleichen nur die aktuelle Liste, da wir davon ausgehen können, dass Personen auf der Serverliste nur vom System überschrieben werden können.
Fast fertig – jetzt fehlt nur noch LoadPeople:
Der Prozess ist hier so ziemlich der gleiche wie weiter oben, nur andersherum.
Jetzt müssen wir nur noch read.py und admin.py anpassen, um die Änderungen an den Klassifizierungsdefinitionen zu reflektieren. Dazu müssen Sie einfach nur den ursprünglichen NFC-Klassifizierungsaufruf ändern:
self=NFC('pi.xml','http://someurl.com/api/People','http://someurl.com/api/Achievements','http://someurl.com/api/Joins')
Endlich – wir sind fertig! Wenn Sie jetzt read.py ausführen, sollte jede Person zur Datenbank hinzugefügt werden.