Intégration de l'api Google Calendar en REST dans une application C# Version 1.0
2 Introduction : Ce tutoriel s adresse aux développeurs souhaitant intégrer l API Google Calendar dans leur application en REST. Il expose brièvement le protocole oauth 2.0 utilisé par l API Google Calendar, décrit comment créer une demande d autorisation d accès et expose les principales méthodes d accès au calendrier. A propos du protocole oauth2 : OAuth2 est la version 2 du protocole OAuth. Ce protocole permet à des applications tierces d obtenir un accès limité à un service disponible via HTTP par le biais d une autorisation préalable du détenteur des ressources. L accès est demandé par le client, qui peut être un site internet ou une application mobile. Si les ressources n appartiennent pas au client, alors ce dernier doit obtenir l autorisation de l utilisateur final, sinon il peut directement obtenir l accès en s authentifiant avec ses propres identifiants La version 2 est censée simplifier la version précédente du protocole et à faciliter l interopérabilité entre les différentes applications. 1- Enregistrement de votre application dans la console de développement Google : Avant toute chose, votre application doit être enregistrée dans la console de développement Google, pour cela, vous devez vous rendre à l adresse https://console.developers.google.com/project et créer un nouveau projet après s'être identifié avec un compte Gmail: Ensuite, vous devez récupérer le certificat de votre application en allant sur APIs & auth, Credentials, puis Create Client Id, vous aurez l écran suivant :
3 Sélectionnez ensuite installed Application, puis Other, Cliquez ensuite sur Create Client ID Ensuite, télécharger le fichier JSON qui contient le certificat de votre application.
4 Le fichier qu on appellera Credentials.Json aura cette forme : "installed": "auth_uri":"https://accounts.google.com/o/oauth2/auth", "client_secret":"xxxxxxxxxxxxxxxxxxxxxxxxxx", "token_uri":"https://accounts.google.com/o/oauth2/token", "client_email":"", "redirect_uris":[ "urn:ietf:wg:oauth:2.0:oob", "oob" ], "client_x509_cert_url":"", "client_id":"xxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com", "auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs" Remarque : Dans l onglet consent screen, vous pouvez personnaliser la page de demande d autorisation que verront les utilisateurs. 2- Création de la demande d autorisation d accès à l agenda, et récupération des Tokens: Pour que votre application puisse accéder à l agenda d un utilisateur, ce dernier doit donner une autorisation sous forme de Tokens, Nous allons développer les étapes pour créer la demande d autorisation qui sera affichée aux utilisateurs: 2.1 Objet Credential : Cet objet va recevoir le certificat de l'application et sera chargé à partir du contenu du fichier Credential.Json que vous auriez récupéré précédemment. Public class installed public Credential credentials get; set; public class Credential public string auth_uri get;set; public string client_secret get;set; public string token_uri get;set; public string client_email get;set; public string[] redirect_uris get;set; public string client_x509_cert_url get;set; public string client_id get;set; public string auth_provider_x509_cert_url get;set;
5 2.2 Demande d autorisation d accès: Après avoir récupéré le contenu le certificat de l'application (credential), nous allons construire l'url à laquelle seront redirigés les utilisateurs dans le processus de demande d'autorisation, la méthode suivante expose la façon de construire l'url. public string GenerateGoogleOAuthURL (Credential ocredential) string surlgenerategoogleoauthurl = "https://accounts.google.com/o/oauth2/auth? =0&redirect_uri= 1&response_type=2&client_id=3&state= 4&access_type= 5&approval_prompt=6"; string surlprivatefeed="https://www.googleapis.com/auth/calendar"; string sredirecturl="urn:ietf:wg:oauth:2.0:oob"; string sresponsetype="code"; string sgenerateurlstate = string.empty; string sgenerateurlaccesstype="offline"; string sgenerateurlapprovalprompt="auto"; string scope=urlencodeforgoogle(surlprivatefeed).replace("%20","+"); string redirect_uri_encode=urlencodeforgoogle(sredirecturl); string surl = string.format(surlgenerategoogleoauthurl, scope,redirect_uri_encode, sresponsetype, ocredential.client_id, sgenerateurlstate, sgenerateurlaccesstype,sgenerateurlapprovalprompt); return surl; private string UrlEncodeForGoogle(string url) string UnReservedChars = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456789- _.~"; var result= new StringBuilder(); foreach (char symbol in url) if(unreservedchars.indexof(symbol)!=-1) result.append(symbol); else result.append('%'+string.format("0:x2",(int) symbol)); return result.tostring(); Remarque : La procédure UrlEncodeForGoogle permet d encoder les caractères non admis dans l Url.
6 L'url précédemment créée permettra aux utilisateurs de donner leur consentement, quand on navigue vers cette Url on a cet écran : Lorsque l utilisateur clique sur accepter, son code d accès à l application est affiché comme illustré sur l image suivante : La première étape qui consiste à récupérer l autorisation de l utilisateur sous forme d un code est finie. L étape suivante consiste à récupérer les Tokens à partir du code d'accès.
7 2.3 Objet UserToken: Les Tokens sont des chaines de caractères générées par le serveur d autorisation et sont émis lorsque le client en fait la demande, Access Token : Permet au serveur de ressources d autoriser la mise à disposition des données d un utilisateur. Il a une durée de vie limitée qui est définie par le serveur d autorisation (dans ce cas de Google Calendar, sa durée est de 60 minutes). Refresh Token : Délivré au même moment que le Token d accès(access Token) mais n est en revanche pas envoyé lors de chaque requête du client vers le serveur de ressources. Il sert simplement rafraichir le token d accès lorsque celui-ci est arrivé à expiration. Pour manipuler les Tokens dans le code nous allons créer un objet UserToken qui aura la structure suivante: public class UserToken public string Login get;set; public string access_code get;set; public string access_token get;set; public string token_type get;set; public string expires_in get;set; public string refresh_token get;set; public DateTime Refresh_date get;set; 2.4 Récupération des Tokens à partir du code d accès: Cette étape consiste à obtenir les Tokens d'accès, en partant du code récupéré précédemment par l'utilisateur, notez bien que dans le cas de Google Calendar, le code récupéré dans l étape 2.2 est valable pendant 10 minutes, passé ce délai le code est obsolète, il faudra donc l'échanger contre les Tokens pour pouvoir interroger le calendrier de l'utilisateur. La méthode suivant détaille comment obtenir les Tokens correspondant à l utilisateur à partir du code d accès:
8 public UserToken GetUserTokenByCode(string scode, Credential credential) string surlrefreshaccestoken = "https://accounts.google.com/o/oauth2/token"; string scontenttypeurlencoded = "application/x-www-form-urlencoded"; string sdataforgettoken = "code=0&client_id=1&client_secret=2&redirect_uri= 3&grant_type=4"; string sredirecturl = "urn:ietf:wg:oauth:2.0:oob"; string sgranttypegetcode = "authorization_code"; UserToken MyToken = new UserToken(); string result = string.empty; HttpWebRequest request = HttpWebRequest.Create(sUrlRefreshAccesToken) as HttpWebRe quest; request.method = WebRequestMethods.Http.Post; request.keepalive = true; request.contenttype = scontenttypeurlencoded; string param = string.format(sdataforgettoken, scode, credential.client_id, creden tial.client_secret, sredirecturl, sgranttypegetcode); var bs = Encoding.UTF8.GetBytes(param); try using (Stream reqstream = request.getrequeststream()) reqstream.write(bs, 0, bs.length); using (WebResponse response = request.getresponse()) var sr = new StreamReader(response.GetResponseStream()); result = sr.readtoend(); sr.close(); if (result!= null) JObject token = JObject.Parse(result); MyToken.access_token = (token["access_token"]).tostring(); MyToken.expires_in = (token["expires_in"]).tostring(); MyToken.refresh_token = (token["refresh_token"]).tostring(); MyToken.token_type = (token["token_type"]).tostring(); MyToken.Refreshdate = DateTime.Now; catch (WebException) throw; catch (Exception) throw; return MyToken; 2-5 Rafraîchissement du Token d accès : Avant de faire une quelconque opération sur l agenda google, on doit toujours s assurer que Token d accès est toujours valable, sinon la demande sera rejetée, La méthode suivante déroule le traitement nécessaire pour rafraîchir le Token d'accès, Il faut savoir que les Token d accès sont valables 1 heure à partir de leur obtention.
9 public UserToken RefreshAccessToken(UserToken ToKen, Credential credential) UserToken MyToken = null; WebRequest; HttpWebRequest request = HttpWebRequest.Create(Constante.UrlRefreshAccesToken) as Http string result = null; request.method = WebRequestMethods.Http.Post; request.keepalive = true; request.contenttype = Constante.ContentTypeUrlEncoded; string param = string.format(constante.dataforrefreshtoken, ToKen.refresh_token, crede ntial.client_id, credential.client_secret, Constante.GrantTyperefreshToken); var bs = Encoding.UTF8.GetBytes(param); tryusing (Stream reqstream = request.getrequeststream()) reqstream.write(bs, 0, bs.length); using (WebResponse response = request.getresponse()) var sr = new StreamReader(response.GetResponseStream()); result = sr.readtoend(); sr.close(); if (result!= null) JObject token = JObject.Parse(result); MyToken = new UserToken(); MyToken.access_token = (token["access_token"]).tostring(); MyToken.token_type = ToKen.token_type; MyToken.expires_in = DateTime.Now.ToString(); MyToken.refresh_token = ToKen.refresh_token; MyToken.LoginGmail = ToKen.LoginGmail; MyToken.access_code = ToKen.access_code; MyToken.UserNumber = ToKen.UserNumber; MyToken.Errone = ToKen.Errone; catch (WebException e) throw; catch (Exception ex) throw; return MyToken;
10 Nous avons à présent récupéré les tokens de l utilisateur, ce qui nous permettra d accéder à son agenda. 1- Exposition des principales méthodes d'accès à l'agenda: L'API Google Calendar autorise plusieurs méthodes pour la gestion des agendas des utilisateurs, nous allons dérouler les principales méthodes de gestion du calendrier principal.dans ce qui suit, nous travaillerons sur l agenda principal qui a pour identifiant le nom du compte associé (Si le compte Google de l utilisateur est Example@gmail.com, son agenda principal aura pour identifiant Example@gmail.com) 3-1 Les principaux objets utilisés: Pour faciliter la sérialisation des objets, nous avons gardé la même syntaxe que Google, L objet «Item» Contient toutes les informations relatives à un événement (rendez-vous) dans l agenda Google. public class Item public string summary get;set; public string kind get;set; public string etag get;set; public string id get;set; public string status get;set; public string htmllink get;set; public string created get;set; public string updated get;set; public string location get;set; public Creator creator get;set; public Organizer organizer get;set; public Start start get;set; public End end get;set; public string icaluid get;set; public int? sequence get;set; public List<Attendee> attendees get;set; public Reminders reminders get;set; public string description get;set; public string colorid get;set; public class Start public string datetime get;set; public string timezoneget;set; public class End public string datetime get;set; public string timezoneget;set; 3-2 Le format Json: L échange de données avec Google Calendar se fera exclusivement au format Json, pour cela vous aurez besoin d un outil pour sérialiser les objets au format Json, dans ce cas nous utiliserons la bibliothèque «Newtonsoft.Json»(https://github.com/JamesNK/Newtonsoft.Json). Voici une méthode qui permet de sérialiser un objet item au format Json :
11 public string Serialize (Object oobject) JsonSerializerSettings settings = new JsonSerializerSettings(); settings.nullvaluehandling = NullValueHandling.Ignore; var json = JsonConvert.SerializeObject( oobject, Formatting.Indented, settings); return json.tostring(); Remarque : il est important d ignorer les propriétés nulles, sinon le Json sera généré avec la valeur null pour certaines propriétés la demande sera alors rejetée. 3-3 Lister les rendez-vous dans un agenda: Pour récupérer la liste des rdv dans un agenda, on exécute une requête HTTP en GET sur le serveur en incluant dans l'entête le Token d'accès, nous avons la possibilité d ajouter un tas de paramètres comme la date de dernière mise à jour, la date minimum de début, la date maximum de début. Public List<Item> GetAllEvents (UserTokenoUserToken, stringnextpagetoken="") Strings Url ="https://www.googleapis.com/calendar/v3/calendars/0/events"; HttpWebRequest request; String result =null; JavaScriptSerializer serializer = new JavaScriptSerializer(); List <Item> EventList = newlist<item>(); HttpWebResponse repons = null; Request = (HttpWebRequest)HttpWebRequest.Create(String.Format(sUrl,oUserToken.Login)); request.method = WebRequestMethods.Http.Get; request.keepalive = true; request.headers.add(httprequestheader.authorization,string.format("bearer0",ousertoken.access_code)); request.timeout=3500; try repons =(HttpWebResponse)request.GetResponse(); WebResponse response=request.getresponse(); Var sr= new StreamReader(response.GetResponseStream()); Result = sr.readtoend(); sr.close(); RootObject jsonobject = serializer.deserialize<rootobject>(result); EventList = jsonobject.items; String nextpage = jsonobject.nextpagetoken; if (!String.IsNullOrEmpty(nextPage)) EventList.AddRange(GetAllEvents(oUserToken,nextPage)); catch(webexception) if(repons!=null&&repons.statuscode==httpstatuscode.forbidden) repons.close(); returneventlist;
12 Remarque : si le nombre de rendez-vous est important, Google renvoie plusieurs pages de résultats pour éviter des trames trop longues, pour savoir s il y a une trame supplémentaires de résultats on vérifie si le Token «nextpagetoken» contient une valeur, si c est la cas, il faut ré-exécuter la même requête en incluant ce paramètre pour récupérer le contenu de la page suivante. 3-4 Créer un rendez vous: Pour créer un rendez-vous, il faut exécuter une requête en POST en incluant comme paramètre dans l'entête le Token d'accès, et en dans le corps de la requête passer l'objet item au format Json. public bool insertevent(itemoitem,usertokenousertoken) bool IsInserted=false; string surlinsertevent="https://www.googleapis.com/calendar/v3/calendars/0/events"; string result=null; WebResponse response; Strings Url = string.format(surlinsertevent,ousertoken.login); String data = SerializeWithoutNullValues(oItem); HttpWebRequest request=httpwebrequest.create(surl)ashttpwebrequest; request.method = WebRequestMethods.Http.Post; request.keepalive=true; request.contenttype="application/json"; request.headers.add(httprequestheader.authorization,string.format("bearer0",ousertoken.access_token)); var bs=encoding.utf8.getbytes(data); using(streamreqstream=request.getrequeststream()) reqstream.write(bs,0,bs.length); try Response = request.getresponse(); varsr=new StreamReader(response.GetResponseStream()); result=sr.readtoend(); sr.close(); IsInserted=true; catch(exceptione) IsInserted=false; //TODO returni sinserted; 3-5 Mettre à jour un rendez-vous : La mise à jour se fait en envoyant une requête en PUT sur le serveur, il faut inclure le code d'accès et spécifier l'identifiant du rendez-vous à mettre à jour. Notez également que vous devez incrémenter la propriété «sequence» pour que la mise à jour puisse se faire, voici la méthode permettant de mettre à jour un rendez-vous :
13 publicboolupdateevent(itemoitem,usertokenousertoken) bool bisupdated=false; string surlupdateevent = "https://www.googleapis.com/calendar/v3/calendars/0/events/1"; try //Onincrémentelavaleurduchampséquence oitem.sequence = oitem.sequence+1; HttpWebRequest request=null; String surl=string.format(surlupdateevent,ousertoken.login,oitem.id); string data= SerializeWithoutNullValues(oItem); request =HttpWebRequest.Create(sUrl)asHttpWebRequest; request.contenttype="application/json"; request.method=webrequestmethods.http.put; request.keepalive=true; request.timeout=3000; request.headers.add(httprequestheader.authorization,string.format("bearer0",ousertoken.access_token)); var bs=encoding.utf8.getbytes(data); using(streamreqstream=request.getrequeststream()) reqstream.write(bs,0,bs.length); HttpWebResponse repons =(HttpWebResponse)request.GetResponse(); bisupdated = true; request.abort(); catch(webexception e) bisupdated=false; return bisupdated;
14 3-6 Supprimer un rendez-vous : Pour supprimer un rendez-vous dans l agenda Google,il faut envoyer une requête HTTP en DELETE sur le serveur, en incluant dans l'entête le Token d'accès, il faut également disposer de l'identifiant du rendez-vous à supprimer. Public bool DeleteEvent (UserTokenoUserToken,stringEventId) String data = string.empty; String surldeleteevent = "https://www.googleapis.com/calendar/v3/calendars/0/events/1"; Bool bisdeleted = false; String surl = string.format(surldeleteevent,ousertoken.login,eventid); HttpWebRequest request =(HttpWebRequest)WebRequest.Create(sUrl); request.method="delete"; request.contenttype="application/json"; request.headers.add(httprequestheader.authorization,string.format("bearer0",ousertoken.access_token)); try var bs= Encoding.UTF8.GetBytes(data); using(streamreqstream=request.getrequeststream()) reqstream.write(bs,0,bs.length); using(httpwebresponseresponse=(httpwebresponse)request.getresponse()) if(response.statuscode==httpstatuscode.nocontent) bisdeleted = true; else bisdeleted = false; catch(exception) bisdeleted = false; returnbisdeleted;
15 Conclusion : En plus des opérations principales sur les agendas citées auparavant, l'api autorise aussi des opérations sur les calendriers, on peut notamment créer, modifier ou supprimer un calendrier, mais également lister l'ensemble des calendriers et leurs configurations. Cette façon d interroger l Api Google Calendar est très facile à mettre en œuvre mais nécessite la gestion des Tokens d'accès. Je vous invite à aller sur ce lien (https://developers.google.com/oauthplayground/) il vous permet de tester toutes les APIs Google, et de voir toutes les opérations possibles avec l'api Google, ce lien est très utile pour tester vos méthodes. Références : https://developers.google.com/oauthplayground/ https://developers.google.com/google-apps/calendar/?hl=fr https://console.developers.google.com/project/ https://oauth.net/2/