Utiliser api avec Angular pour débutant

a marqué ce sujet comme résolu.

Bonjour !

je viens vous demander de l'aider car je me suis lancer dans un petit projet perso et j'ai un peu de mal à arriver à mes fins. Pour remettre les choses dans leurs contexte, je suis amateur en dév web, je fais ça par envie et j'essaye de progresser en me lançant des défis. J'avais beaucoup entendu parler d'angular js et ayant regarder des vidéos dessus je trouvais ça super cool. Comme je voulais aussi apprendre à crée des applications mobile via Cordova, je me suis dis : "allons y, développons une première application mobile en utilisant Angular et Cordova". En temps que fan du jeu league Of Legends et utilisateur de windows Phone j'ai décidé de crée une application simple qui permet d'avoir les résultats des matchs joués.

Voici le résultat que j'ai pu obtenir :

accueil application

résultats des matchs

Maintenant j'aimerai passer à l'étape suivante : récupérer les données affichées (résultats des matchs) via un serveur distant. En théorie je vois plus ou moins comment faire : utiliser une api REST et le service http d'Angular.

En pratique je suis complétement perdu :

1) Est-ce utile d'avoir une API REST sachant que j'ai besoin uniquement de la lecture ? (un script cron sur le serveur s'occupera de mettre à jour les données de la bdd).

2) En framework php je ne sais utiliser que CodeIgniter. J'ai réussit à trouver le tutoriel suivant expliquant comment crée une api REST. J'ai l'impression que c'est simple, dans mon cas il me suffit d'avoir seulement la fonction index qui récupère toutes les données et de modifier la route. En pratique quand j'ouvre ma page de test dans mon navigateur j'ai bien un objet json qui s'affiche.

Comment être tester si mon api fonctionne ? Le fait d'afficher un objet json quand on charge la page est-il suffisant ?

3) Par contre je ne comprends absolument pas comment me connecter à cette page via angular js.. J'ai essayer d'utiliser le service http d'angular présenté ici de cette façon :

1
2
3
4
5
6
7
$http.get('http://localhost/Api-resultats-lcs/').
  success(function(data, status, headers, config) {
   alert("success");
  }).
  error(function(data, status, headers, config) {
   alert("error");
  });

Le problème est que ça fait buger mon application angular et ça n'affiche rien. J'ai mis ce code dans le contrôleur de l'application (il y à un seul ctrl). Peut-être que je n'ai pas mis le code au bon endroit ? Je ne comprends en tout cas pas trop comment cela s'utilise :(

Voilà, désolé si mon problème est simple, merci d'avance pour votre aide !

PS: je peux mettre le code js de mon application si ça peut vous aider à mieux comprendre mon problème, idem pour le code php mais celui ci est quasi identique à celui du tuto (juste les noms des fonctions et fichiers qui changent) .

+0 -0

1) Est-ce utile d'avoir une API REST sachant que j'ai besoin uniquement de la lecture ? (un script cron sur le serveur s'occupera de mettre à jour les données de la bdd).

As-tu bien compris ce qu'était une API et une API REST ?

Une API REST est une architecture, qui utilise le protocole http, pour accéder à une ressource grâce à une adresse pour effectuer diverses opérations (souvent lire, écrire, modifier, …). J'ai un peu simplifié mais l'idée est la.

Si on prend l'exemple de l'api REST de "Zeste De Savoir", si tu te rend sur la page de la documentation. Tu peux voir qu'on met à disposition plusieurs adresses, par exemple: https://zestedesavoir.com/api/#!/membres qui te renvoi la liste des membres. C'est bien une API REST car on accède à une ressource, sur cet exemple, des membres, à une adresse, ici, api/#!/membres, pour accéder à une opération, lister tous les membres.

On peut fournir une API REST, uniquement pour un type d'opération la lecture. Tu supprimera juste le code pour ajouter, modifier et supprimer.

2) En framework php je ne sais utiliser que CodeIgniter. J'ai réussit à trouver le tutoriel suivant expliquant comment crée une api REST. J'ai l'impression que c'est simple, dans mon cas il me suffit d'avoir seulement la fonction index qui récupère toutes les données et de modifier la route. En pratique quand j'ouvre ma page de test dans mon navigateur j'ai bien un objet json qui s'affiche.

C'est que c'est bon. Tu as donc exposé des ressources, des matches lcs, à une adresse http://localhost/Api-resultats-lcs/, pour l'opération permettant de lister des matches des lcs, a un format qui est le JSON.

3) Par contre je ne comprends absolument pas comment me connecter à cette page via angular js.. J'ai essayer d'utiliser le service http d'angular présenté ici de cette façon :

Le code que tu nous donne me parait correct, après je connais pas bien Angular JS, si tu veux tenter de débugger, tu peux déja regarder, si tu rentre l’adresse, http://localhost/Api-resultats-lcs/ dans ton navigateur, tu as bien du JSON qui s'affiche. Sinon tu peux regarder dans ta console JS, si tu as pas d'erreurs.

+0 -0

Je me demande si je n'ai pas deux problèmes en fait :

1) Après vérification je ne sais pas trop si mon api renvois bien un objet Json ou pas… Voici un screen qui montre ce que ma page affiche :

test

On dirait plutôt un tableau qu'un objet json non ? Voici à titre de comparaison ce que donne une requête à l'api d'instagram. C'est une erreur, mais on voit bien la différence, l'objet commence par des parenthèses et est affiché avec une police différente :

test

Voici mon code source coté php :

  • controleur :
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Accueil extends CI_Controller {

    public function index()
    {
        header("Access-Control-Allow-Origin: *");
        $data = [];
        $this->load->model('main_model'); // on charge le model
        $data['matchs'] = $this->main_model->get_matchs('0'); // on récupe les matchs
        $json = json_encode($data['matchs']); // on transforme en Json
        echo($json);    // on affiche le Json
    }
}

Et voici le modéle:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?php  if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Main_model extends CI_Model
{
    // retourne la liste complete des matchs en fonction de la region
  public function get_matchs($region){
        $resultat = $this->db->select('*')
                    ->from('matchs')
                    ->where('region',$region)
                    ->get()
                    ->result();
        return $resultat;
    }

}

Pourtant je ne comprends pas trop, j’utilise bien json_encode qui devrait donc bien me renvoyer du json non ?

2) Si j'utilise l'url de test de l'api d'instagram dans mon application angular mon appli ne fonctionne plus non plus, donc il y à bien un problème à ce niveau là aussi… Si quelqu’un qui connait bien angular passe par là :)

+0 -0

1) Après vérification je ne sais pas trop si mon api renvois bien un objet Json ou pas… Voici un screen qui montre ce que ma page affiche :

test

On dirait plutôt un tableau qu'un objet json non ?

C'est du JSON. Tu as juste un tableau d'objet qui contient plein d'objet JSON. Le JSON c'est juste un format d'échange entre un serveur (ton PHP) et un client (ton application AngularJS). Tu aurais très bien pu choisir un autre format d'échange comme le XML, il faut juste que quand tu "décodera" le message dans ton application AngularJS, tu sache quel format d'échange utilise ton serveur.

Tu peux aussi très bien choisir comme format d'échange les ; ou les , ou les | (C'est du troll, hein ^^). Ton PHP renverrais donc une chaîne de caractère, comme ça: "id,1,region,0,weekNumber,1 …" . Il faudrait juste que dans ton application AngularJS quand tu reçoit la réponse, tu découpe ta réponse sur des ",". Tout ça pour dire que le format d'échange, importe peu, du moment que tu sais le décoder dans ton client AngularJS. Le JSON étant très courrant et le plus utilisé, c'est surement un bon choix.

2) Si j'utilise l'url de test de l'api d'instagram dans mon application angular mon appli ne fonctionne plus non plus, donc il y à bien un problème à ce niveau là aussi… Si quelqu’un qui connait bien angular passe par là :)

Rien dans la console JS de ton navigateur ? Tu as un exemple, ici, ultra simple avec lequel tu peux jouer. Tu peux pas nous montrer ton controlleur ?

+1 -0

OMG en fait j'avais oublier d'injecter le $http en paramètre du contrôleur principale…

Du coup je teste ça ! Voici sinon le code de mon ctrl angular :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
var app = angular.module("lcs-result",[]);
app.controller("main-ctrl",function($scope){

    $scope.page_title = "Regions"; // titre initial de la page
    // met a jour le header de l'apli
    $scope.update_title = function(value){
        $scope.page_title = value;
    }

    // indique la région consultée : 
    $scope.regionCourante = null;
    $scope.selectionRegion = function(region){
        $scope.regionCourante = region;
        $scope.weekShow = null;
    };

    // active ou desactive l'affichage des matchs de la semaine passée en paramétres :
    $scope.show = function(week){
        if($scope.weekShow==week){
            $scope.weekShow = null; // referme l'affichage 
        }
        else{
            $scope.weekShow = week; // indique la semaine dont il faut montrer les resultats
        }
    }

    $scope.weekShow = null;
    $scope.showMatchs = function(week){
        if(week==$scope.weekShow ){
            return true;
        }
        else{
            return false;
        }
    };








    //données de tests pour les résultats des matchs
    $scope.dossier = [
        {
            region:"lcsna",week:[
                {
                weekNumber:"8",matchs:[
                    {team1:"CLG", team2:"Cloud9", score1:"1", score2:"0", day:"day1"},
                    {team1:"Cloud9", team2:"CLG", score1:"0", score2:"1", day:"day1"},
                    {team1:"Gravity", team2:"Winterfox", score1:"1", score2:"0", day:"day1"},
                    {team1:"Liquid", team2:"TSM", score1:"1", score2:"0", day:"day1"},
                    {team1:"CLG", team2:"Cloud9", score1:"1", score2:"0", day:"day1"},
                    {team1:"Cloud9", team2:"CLG", score1:"0", score2:"1", day:"day2"},
                    {team1:"Gravity", team2:"Winterfox", score1:"1", score2:"0", day:"day2"},
                    {team1:"Liquid", team2:"TSM", score1:"1", score2:"0", day:"day2"},
                    {team1:"Gravity", team2:"Impulse", score1:"1", score2:"0", day:"day2"},
                    {team1:"CLG", team2:"Team8", score1:"1", score2:"0", day:"day2"}]
                }   
            ],  
        }
    ];

});
+0 -0

Alors avec la page de test que tu m'as passé ça fonctionne parfaitement, merci :)

J'ai l'impression d'être parfaitement perdu au niveau de mon json… Mon json est une chaine de caractère du coup si je fais quelque chose du genre echo $json[0] au lieu d'afficher le premier objet ça affiche juste "["....

Pourtant pour un autre projet j'avais déja utiliser json_encode et le résultat était un tableau qu'on pouvait parcourir… je suis un peu perdu :(

+0 -0

Quand tu lui envois la réponse à ton client, il faut lui préciser que tu va lui envoyer du json sinon il crois que c'est une chaine de caractére.

À la place de ton <?php echo($json);, tu devrais avoir,

1
2
3
4
<?php
 $this->output
    ->set_content_type('application/json')
    ->set_output(json_encode(array($json)));

Avec leur adresse (http://www.w3schools.com/angular/customers.php), ça marche ?

Dernier recours, si rien ne marche, à la place de ton <?php echo($json);, tente un,

1
2
3
4
<?php
 $this->output
    ->set_content_type('application/json')
    ->set_output(json_encode(array("matches" => $json)));
+1 -0

Ça marche !

Merci beaucoup pour tes précieux conseils ! Grâce à toi j'ai réussit la partie 2 de mon projet: réaliser une api afin de récupérer les résultats, merci beaucoup !

Maintenant je m'occupe de la 3éme partie : réaliser un parser php qui récuperera automatiquement les résultats des matchs pour les ajouter à la bdd. N'ayant encore jamais fait ça je vais bien m'amuser, mais ça devrait être instructif :)

+0 -0

Bonjour,

Je me permet de revenir vers vous car j'ai un petit problème un peu étrange …

J'ai finalement réussit à trouver une api déja toute faite qui renvois les données que je veux ce qui est super pratique et va me faire gagner un temps fou (plus besoin de crée ma propre api et un parser).

L'api est disponible ici et est trés simple d'utilisation. Par exemple si je veux le classement des équipes en europe, il me suffit de demander l'url suivante : http://na.lolesports.com/api/standings.json?tournamentId=225

Si on tape cette url dans le navigateur tout va bien on voit bien les résultats sous forme d'un objet Json. Le problème et que je n'arrive pas à récuperer ça avec le service http d'angular.

En effet j'obtient un echec si je demande :

1
2
3
4
5
6
7
$http.get('http://na.lolesports.com/api/standings.json?tournamentId=225').
    success(function(data, status, headers, config) {
        alert("success");
    }).
    error(function(data, status, headers, config) {
    alert("error");
    });

Alors que si je remplace l'url par celle d'exemple donnée plus haut par Hugo (http://www.w3schools.com/angular/customers.php) j’obtiens bien un success. Je ne comprends pas trop pourquoi dans le cadre de l'api de lolesport je n'arrive pas à récuperer l'objet json affiché par la page… :(

+0 -0

J'ai trouvé le problème :)

Il me faut autoriser le 'Access-Control-Allow-Origin' et ajouter ça au header de ma requete d'origine… Je ne sais absolument pas comment faire mais je sais au moins que je dois faire ça :)

+0 -0

Non ce n'est pas un probléme avec le serveur car c'est une api publique ! Donc elle autorise forcement les requêtes cross domaine (sinon l'api ne sert à rien :p ). Dans tous les cas je n'ai pas accès au serveur.

En fait ça me retourne l'erreur suivante :

XMLHttpRequest cannot load http://na.lolesports.com/api/standings.json?tournamentId=225. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://fiddle.jshell.net' is therefore not allowed access.

J'ai installer une extension Chrome qui ajoute à toutes les requetes "Allow-control-origin-allow: *" et alors ça fonctionne :)

Le problème vient bien de la, il me faudrait si je comprends bien changer mon header de ma requete… Mais je ne sais pas comment on fait ça correctement avec angular vu que je découvre le framework et que je n'avais jamais utilisé d'api auparavant :p

+0 -0

Ha ok :)

je n'ai pas vraiment de "serveur" vu que j'ai juste une page html et un fichier js , mais je vois ce que tu veux dire !

Voici mon code principal qui récupere les données :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
var app = angular.module("lcs-result",['angular-toArrayFilter']);


app.controller("main-ctrl",function($scope,$http){
    // RECUPERATION DES DONNES VIA L API DE RIOT 


    $http.get(url_res).
    success(function(data, status, headers, config) {
        // faire des trucs sur les données 
    }).
    error(function(data, status, headers, config) {
        alert('error'); // oups ça ne me marche pas!
    });

});

Je ne sais pas où je dois bidouiller pour modifier mon header de ma requete http :(

+0 -0

Justement, c'est… le serveur qui renvoie les headers HTTP. Or si tu n'as pas de serveur (si je comprends bien, tu testes en local, en ouvrant directement le fichier dans le navigateur), ça risque d'être compliqué.

J'imagine que de toute façon c'est destiné à être mis en ligne, et disponible à d'autres utilisateurs non ? Si oui, alors prends la peine d'installer un serveur Web, même pour ne lire qu'une page, et si non, tu peux garder ta solution actuelle :)

Non malheureusement ce n'est pas destiné à être mis en ligne, le but pour moi est de crée une application mobile avec Cordova ! Je n'ai jamais fait d'appli mobile mais je ne crois pas qu'il puisse y avoir de serveur, donc mon appli doit impérativement fonctionner sans coté serveur :)

Si je comprends bien ce que fait l’extension Chrome que j'ai rajouté, elle modifie simplement le Header des requêtes que j’envoie vers certains noms de domaines pour ajouter le Allow Control Origine : https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi

Donc ça doit pouvoir se faire sans utiliser de serveur :) Il faut juste que je trouve comment xD.

+0 -0

Elle modifie simplement le Header des requêtes que j’envoie vers certains noms de domaines

Absolument pas. Tu n'as pas compris commence le CORS fonctionne.

Ce qu'elle fait, c'est qu'elle injecte dans n'importe quelle réponse HTTP le header Access-Control-Allow-Origin:*

Et Théo a raison, c'est normalement au serveur qui sert LA PAGE (pas l'API) d'autoriser le CORS.

Dans ton cas il n'y en a pas, donc tu es obligé d'utiliser ton extension qui injecte le header http y compris pour une page servie depuis ton disque dur.

Normalement avec Cordova tu n'auras pas besoin de ça. http://stackoverflow.com/questions/21297169/cors-and-phonegap-apps

+1 -0

En fait je ne sais pas vraiment ce qu'est le CORS, je découvre ça petit à petit pour les besoins de mon application :)

Si je comprends bien pour faire du cross domaine il faut deux autorisations : Une de l'API qui s'autorise à accepter les requêtes externes, et une du demandeur qui s'autorise à accepter les réponses externes ?

Je penses que je comprends mieux le problème (arrêtez moi si je me trompe :p ) : dans une api normale le fournisseur de l'api délivre les deux autorisations (il accepte de répondre et reponds avec le bon header). Dans mon cas l'api accepte gentillement de renvoyer des données, mais avec le mauvais header, ce qui me bloque par défaut.

Je comprends d'où cela vient: en cherchant un peu je me rends compte que malheureusement l'api que j'utilise est encore en cours de dév et n'est pas officielle même si elle devrait bientôt l'être. Elle comporte encore des erreurs comme j'ai pu m'en rendre compte:les données pour les zones Corée et Chine sont incomplètes, il manque la moitié des matchs ce qui fait qu'en pratique je ne peux pas utiliser l'api pour mon usage (ne donner les résultats que pour l'europe et les USA n'est pas très intéressant car ses zones sont largement suivies en occident). Donc pour éviter que les gens utilisent leurs api avec des données erronés ils mettent un header qui bloque, indiquant "tu devrais pas utiliser notre api y à encore des bugs".

Je vais donc mettre ce petit projet en pause, le temps que l'api fonctionne correctement :)

Concernant Cordova je dois t'avouer que là aussi c'est la première fois que j'essaye de l'utilisé et pour l'instant je n'ai touché à aucun code lié à Cordova. J'ai crée une nouvelle application cordova et dans le fichier index.html j'ai ajouté mon html et mon angular. Si je comprends bien ce que tu m'expliques, j'ai juste à rajouté une balise dans mon code (je la rajoute à l'index? N'importe où?) pour ajouter un domaine à la whitelist. (comme je veux en priorité build pour windows phone je n'ai à priori rien besoin de faire si j'en crois le lien, windows phone accepte tous les requêtes de tous les domaines par défaut).

Merci pour tous ces conseils, et désolé si ne maitrise pas plein de choses "basiques", je découvre plein de choses en même temps ;)

+0 -0

Si je comprends bien pour faire du cross domaine il faut deux autorisations : Une de l'API qui s'autorise à accepter les requêtes externes, et une du demandeur qui s'autorise à accepter les réponses externes ?

Effectivement, certaine API publique n'active pas le CORS ce qui est frustrant…
http://enable-cors.org/index.html ce site explique (en anglais) pourquoi il est important d'activer le CORS sur son API (coté serveur).

+0 -0

Je penses que dans mon cas c'est normal comme l'api n'est pas finalisée. Ils coupent la poire en deux : "ok on vous réponds mais on active pas le CORS car le service n'est pas sur à 100% donc on vous prévient".

Je vais essayer de continuer mon projet en utilisant que les données qui sont fonctionnelles. l'application sera moins utile que prévue mais ça me fera une première expérience avec Cordova ;)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte