{"id":828,"date":"2020-03-16T22:58:00","date_gmt":"2020-03-16T21:58:00","guid":{"rendered":"https:\/\/louis.hatier.me\/blog\/?p=828"},"modified":"2021-03-05T22:21:34","modified_gmt":"2021-03-05T21:21:34","slug":"demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql","status":"publish","type":"post","link":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/","title":{"rendered":"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL"},"content":{"rendered":"<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-medium wp-image-830\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png\" alt=\"Vue.js, Apollo, GraphQL, Hasura, PostgreSQL\" width=\"300\" height=\"94\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png 450w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a>Voici comment d\u00e9marrer tranquillement une application avec un front Vue.js qui interroge une API GraphQL.<\/p>\n<p>Le tout sans faire trop d&rsquo;effort \u00e0 l&rsquo;aide d&rsquo;Hasura et d&rsquo;Apollo.<\/p>\n<p>\u00c7a fait pas mal de technos :<\/p>\n<ul>\n<li style=\"font-weight: 400;\"><strong>Vue.js<\/strong> : framework front JS<\/li>\n<li style=\"font-weight: 400;\"><strong>Apollo<\/strong> : composant qui permet d\u2019interroger une API GraphQL depuis le front<\/li>\n<li style=\"font-weight: 400;\"><strong>GraphQL<\/strong> : type d\u2019API cr\u00e9\u00e9 par Facebook en 2012 (diff\u00e9rent de <a href=\"https:\/\/louis.hatier.me\/blog\/developper-api-rest-symfony-3\/\">REST<\/a> et <a href=\"https:\/\/louis.hatier.me\/blog\/soap-zend-framework\/\">SOAP<\/a>)<\/li>\n<li style=\"font-weight: 400;\"><strong>Hasura<\/strong> : outil open-source qui permet d\u2019exposer une API GraphQL depuis une base de donn\u00e9e PostgreSQL<\/li>\n<li style=\"font-weight: 400;\"><strong>PostgreSQL<\/strong> : le SGBD qui va stocker les donn\u00e9es<\/li>\n<\/ul>\n<p><!--more--><\/p>\n<p>Pour re-resum\u00e9 : en installant l\u2019outil Hasura sur un serveur PostgreSQL, on expose une API de type GraphQL \u00e0 moindre effort.<\/p>\n<p>Ensuite on peut interroger cette API depuis n\u2019importe quel front, en l&rsquo;occurrence on va se concentrer sur Vue.js et le composant Apollo (on peut imaginer qu\u2019Apollo est \u00e0 GraphQL\/JS ce que PDO_MYSQL est \u00e0 MySQL\/PHP).<\/p>\n<p><span style=\"font-size: inherit;\">L\u2019API GraphQL permet de r\u00e9cup\u00e9rer des donn\u00e9es plus finement et en une seule requ\u00eate, contrairement \u00e0 une API REST qui va n\u00e9cessiter une requ\u00eate par type de donn\u00e9e.<\/span><\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/graphql-api.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-835 size-medium\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/graphql-api-300x169.png\" alt=\"GraphQL API\" width=\"300\" height=\"169\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/graphql-api-300x169.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/graphql-api.png 759w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Pour l\u2019exemple on va utiliser des donn\u00e9es <a href=\"https:\/\/data.gouv.fr\" target=\"_blank\" rel=\"noopener noreferrer\">data.gouv.fr<\/a> : la liste des \u00e9quipements sportifs en France.<\/p>\n<h2>Lancer Hasura sur sa machine<\/h2>\n<p>Cr\u00e9er un docker-compose qui charge Hasura et une base PostgreSQL, pour cela deux solutions :<\/p>\n<ol>\n<li style=\"font-weight: 400;\">ajouter un service postgres dans le docker-compose (si on n\u2019a pas Postgres en local)<\/li>\n<li style=\"font-weight: 400;\">cr\u00e9er une base local Postgres sur sa machine<\/li>\n<\/ol>\n<p>Version tout packag\u00e9e avec PostgreSQL int\u00e9gr\u00e9 \u00e0 la stack <a href=\"https:\/\/louis.hatier.me\/blog\/docker-registry-prive\/\">Docker<\/a><br \/>\nFichier <code>docker-compose.yaml<\/code><\/p>\n<pre><code class=\"no-highlight\">version: '3.6'\nservices:\n  postgres:\n    image: postgres\n    ports:\n    - \"5432:5432\"\n    restart: always\n    volumes:\n    - .\/db_data:\/var\/lib\/postgresql\/data\n  graphql-engine:\n    image: hasura\/graphql-engine:v1.1.0\n    ports:\n    - \"8080:8080\"\n    depends_on:\n    - \"postgres\"\n    restart: always\n    environment:\n      HASURA_GRAPHQL_DATABASE_URL: postgres:\/\/postgres:@postgres:5432\/postgres\n      HASURA_GRAPHQL_ENABLE_CONSOLE: \"true\" # set to \"false\" to disable console\n      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log\n      #HASURA_GRAPHQL_ADMIN_SECRET: secret\nvolumes:\n  db_data:\n<\/code><\/pre>\n<p>Version avec PostgreSQL install\u00e9 en local<br \/>\nFichier <code>docker-compose.yaml<\/code><\/p>\n<pre><code class=\"no-highlight\">version: '3.6'\nservices:\n  graphql-engine:\n    image: hasura\/graphql-engine:v1.1.0\n    ports:\n    - \"8080:8080\"\n    restart: always\n    environment:\n      HASURA_GRAPHQL_DATABASE_URL: postgres:\/\/where_to_sport:secret@172.17.0.1:5432\/where_to_sport\n      HASURA_GRAPHQL_ENABLE_CONSOLE: \"true\" # set to \"false\" to disable console\n      HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log\n      #HASURA_GRAPHQL_ADMIN_SECRET: secret\n<\/code><\/pre>\n<p>Manipulation \u00e0 faire sur PostgreSQL (pour la solution 2)<\/p>\n<p>Cr\u00e9ation d\u2019un base de donn\u00e9e :<\/p>\n<pre><code class=\"sql\">CREATE DATABASE where_to_sport;\n<\/code><\/pre>\n<p>Hasura n\u00e9cessite l\u2019extension <em>pgcrypto<\/em> pour fonctionner :<\/p>\n<pre><code class=\"sql\">CREATE EXTENSION IF NOT EXISTS pgcrypto;\n<\/code><\/pre>\n<p>Cr\u00e9ation d\u2019un sch\u00e9ma :<\/p>\n<pre><code class=\"sql\">CREATE SCHEMA app;\n<\/code><\/pre>\n<p>Cr\u00e9ation d\u2019un user pour acc\u00e9der \u00e0 la BDD :<\/p>\n<pre><code class=\"sql\">CREATE ROLE where_to_sport LOGIN password 'secret';\nGRANT ALL ON DATABASE where_to_sport TO where_to_sport;\n<\/code><\/pre>\n<p>Ajout des droits sur la BDD :<br \/>\nFichier <code>\/etc\/postgresql\/11\/main\/pg_hba.conf<\/code> (remplacer <em>11<\/em> par votre version de PostgreSQL).<\/p>\n<pre><code class=\"no-highlight\">host    where_to_sport  where_to_sport  0.0.0.0\/0         md5\n<\/code><\/pre>\n<p>Lancer la stack Docker :<\/p>\n<pre><code class=\"no-highlight\">docker-compose up -d\n<\/code><\/pre>\n<p>Acc\u00e9der \u00e0 Hasura : http:\/\/localhost:8080\/<\/p>\n<h2>I want data !<\/h2>\n<p>On r\u00e9cup\u00e8re le CSV sur <a href=\"https:\/\/www.data.gouv.fr\/fr\/datasets\/recensement-des-equipements-sportifs-espaces-et-sites-de-pratiques\/\" target=\"_blank\" rel=\"noopener noreferrer\">data.gouv<\/a><\/p>\n<p>On l\u2019importe via un outil ou script (DataGrip par exemple).<br \/>\nOn s&rsquo;ajoute deux tables de liaison pour l\u2019exemple (<em>equipements_type<\/em> qui contient le code \u00e9quipement ainsi que son libell\u00e9, et une table <em>departements<\/em>).<\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/data-model.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-839 aligncenter\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/data-model-287x300.png\" alt=\"Data model PostgreSQL\" width=\"287\" height=\"300\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/data-model-287x300.png 287w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/data-model.png 503w\" sizes=\"auto, (max-width: 287px) 100vw, 287px\" \/><\/a><\/p>\n<p>Une fois que notre sch\u00e9ma est ok, il faut indiquer \u00e0 Hasura quelle tables \u201ctracker\u201d et les relations entre elles (il les devine tout seul, il faut juste les activer).<\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-1.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-840 aligncenter\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-1-300x174.png\" alt=\"Hasura data 1\" width=\"300\" height=\"174\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-1-300x174.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-1-768x447.png 768w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-1.png 774w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a> <a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-2.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-841 size-medium\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-2-300x156.png\" alt=\"Hasura data 2\" width=\"300\" height=\"156\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-2-300x156.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-2-768x400.png 768w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-data-2.png 907w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>On peut ensuite s\u2019amuser avec l\u2019outil int\u00e9gr\u00e9 \u00e0 Hasura (GraphiQL) pour faire nos premi\u00e8res requ\u00eates :<\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-842 aligncenter\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql-300x144.png\" alt=\"Hasura GraphiQL\" width=\"300\" height=\"144\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql-300x144.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql-1024x492.png 1024w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql-768x369.png 768w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql-1536x738.png 1536w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/hasura-graphiql.png 1591w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Il reste maintenant \u00e0 d\u00e9marrer une application Vue.js et interroger cette API de mani\u00e8re dynamique.<\/p>\n<p>L\u2019outil Visual Studio Code dispose de plugins GraphQL, Apollo, Vue.js etc.<\/p>\n<h2>Vue.js<\/h2>\n<p>Initier un projet Vue.js avec ce dont vous avez besoin (node-sass, babel, router, eslint\u2026).<\/p>\n<pre><code class=\"no-highlight\">npm run serve\n<\/code><\/pre>\n<p>La page d\u2019accueil par d\u00e9faut s\u2019affiche sur http:\/\/localhost:8081\/<\/p>\n<p>Ajouter le composant Apollo au projet :<\/p>\n<pre><code class=\"no-highlight\">vue add apollo\n<\/code><\/pre>\n<p>Cr\u00e9er un fichier <code>.env<\/code> \u00e0 la racine du projet et ajouter l\u2019url de l\u2019API GraphQL expos\u00e9 par Hasura :<\/p>\n<pre><code class=\"no-highlight\">VUE_APP_GRAPHQL_HTTP=http:\/\/localhost:8080\/v1\/graphql\nVUE_APP_GRAPHQL_WS=ws:\/\/localhost:8080\/v1\/graphql\n<\/code><\/pre>\n<p><code>ws:\/\/<\/code> est le Websocket utilis\u00e9, il permet au back de pusher automatiquement les modifications de data au front, qui pourra ensuite les afficher en temps r\u00e9el (comme un tchat).<\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/dossier-gql.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"alignleft size-full wp-image-856\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/dossier-gql.png\" alt=\"Vue.js GQL\" width=\"223\" height=\"113\"><\/a>Dans l&rsquo;arborescence du projet Vue.js, plut\u00f4t que stocker les requ\u00eates des donn\u00e9es dans le dossier store, on va les stocker dans un dossier <em>graphql<\/em>.<\/p>\n<p>C&rsquo;est ici que seront organis\u00e9 nos requ\u00eates GraphQL, celles qui sont g\u00e9n\u00e9r\u00e9es par l&rsquo;outil GraphiQL d&rsquo;Hasura.<\/p>\n<p>Un fragment fonctionne de la m\u00eame mani\u00e8re qu&rsquo;un include, par exemple si vous avez 10 requ\u00eates qui concernent des Users, et que vous r\u00e9cup\u00e9rez syst\u00e9matiquement les m\u00eames champs (id, name, email), plut\u00f4t que de r\u00e9\u00e9crire ces champs X fois il est pr\u00e9f\u00e9rable de les avoir dans un <em>fragment<\/em> qui sera r\u00e9utilisable.<\/p>\n<p>Voila \u00e0 quoi ressemble la requ\u00eate qui r\u00e9cup\u00e8re les d\u00e9partements :<\/p>\n<pre><code class=\"no-highlight\">query GetDepartements {\n  app_departements(order_by: {libelle: asc}) {\n    id\n    libelle\n  }\n}\n<\/code><\/pre>\n<p>Puis le fragment de ma recherche (<em>equipement_type<\/em> et <em>departement<\/em> \u00e9tant les donn\u00e9es des tables li\u00e9es) :<\/p>\n<pre><code class=\"no-highlight\">fragment equipementsFragment on app_equipements {\n  id\n  cominsee\n  comlib\n  insnom\n  gestiontypeproprietaireprinclib\n  equnom\n  equdouche\n  equanneeservice\n  equnbplacetribune\n  naturesollib\n  naturelibelle\n  equnbvestiairespo\n  equaccueilbuvette\n  equgpsx\n  equgpsy\n  equdatemaj\n  equipement_type {\n    equipementtypecode\n    equipementtypelib\n  }\n  departement {\n    libelle\n  }\n}\n<\/code><\/pre>\n<p>Et enfin la r\u00e9cup\u00e9ration d&rsquo;\u00e9quipements avec les deux crit\u00e8res de recherche et l&rsquo;import du fragment qui s&rsquo;\u00e9crit <code>...equipementsFragment<\/code> :<\/p>\n<pre><code class=\"no-highlight\">#import \".\/EquipementsFragment.gql\"\n\nquery GetAllEquipements($departement_id: Int, $equipement_code: Int) {\n  app_equipements(\n      where: {\n        departement: {id: {_eq: $departement_id}},\n        _and: {\n          equipement_type: {equipementtypecode: {_eq: $equipement_code}}\n          }\n        },\n      order_by: {\n        comlib: asc,\n        equipement_type: {equipementtypelib: asc},\n        insnom: asc\n      }\n    ) {\n    ...equipementsFragment\n  }\n}\n\n<\/code><\/pre>\n<p>Il faut noter que ces requ\u00eates sont uniquement des <em>query<\/em> (\u00e9quivalent du SELECT), il existe \u00e9galement les <em>mutation<\/em> (INSERT, UPDATE, DELETE), et les <em>subscription<\/em> (permet de r\u00e9cup\u00e9rer en live les modifications de donn\u00e9es).<\/p>\n<p>Pour pouvoir utiliser ces requ\u00eates il faut les importer dans le composant (ou la vue) :<\/p>\n<pre><code class=\"js\">import GET_DEPARTEMENTS from '@\/graphql\/GetDepartements.gql'\nimport GET_TYPES_EQUIPEMENTS from '@\/graphql\/GetTypesEquipements.gql'\nimport SEARCH_EQUIPEMENTS from '@\/graphql\/SearchEquipements.gql'\n<\/code><\/pre>\n<p>Le composant Apollo permet d&rsquo;interroger l&rsquo;API avec ces requ\u00eates de mani\u00e8re simple.<\/p>\n<p>Voila le bout de code qui r\u00e9cup\u00e8re la liste des d\u00e9partements et des \u00e9quipements, puis qui g\u00e8re la recherche \u00e0 la validation du formulaire :<\/p>\n<pre><code class=\"js\">export default {\n  name: 'Home',\n  data () {\n    return {\n      departements: [],\n      typesEquipements: [],\n      resultats: null,\n      searchVars: null,\n      searchDepartementId: null,\n      searchEquipementCode: null\n    }\n  },\n  apollo: {\n    app_departements: {\n      query: GET_DEPARTEMENTS,\n      result ({ data }) {\n        this.departements = data.app_departements\n      }\n    },\n    app_equipements_type: {\n      query: GET_TYPES_EQUIPEMENTS,\n      result ({ data }) {\n        this.typesEquipements = data.app_equipements_type\n      }\n    },\n    app_equipements: {\n      query: SEARCH_EQUIPEMENTS,\n      variables () {\n        return {\n          departement_id: this.searchDepartementId,\n          equipement_code: this.searchEquipementCode\n        }\n      },\n      skip () {\n        return !this.searchVars || !this.searchVars.searchDepartementId || !this.searchVars.searchEquipementCode\n      },\n      result ({ data }) {\n        this.resultats = data.app_equipements\n      }\n    }\n  },\n  methods: {\n    search (e) {\n      e.preventDefault()\n      this.searchVars = {\n        searchDepartementId: this.searchDepartementId,\n        searchEquipementCode: this.searchEquipementCode\n      }\n    }\n  }\n}\n<\/code><\/pre>\n<p>L&rsquo;instruction <em>skip<\/em> indique sous quelles conditions la requ\u00eate ne doit <strong>pas<\/strong> \u00eatre lanc\u00e9e, en l\u2019occurrence si nos crit\u00e8res de recherches ne sont pas renseign\u00e9s.<\/p>\n<p>On ajoute \u00e0 \u00e7a le plugin <em>vue2-google-maps<\/em> avec npm et on obtient une application de recherche d&rsquo;\u00e9quipements sportifs :<\/p>\n<p><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-870 aligncenter\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2-300x146.png\" alt=\"Application r\u00e9sultat 2\" width=\"300\" height=\"146\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2-300x146.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2-1024x499.png 1024w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2-768x374.png 768w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2-1536x749.png 1536w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-2.png 1897w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><a href=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1.png\" data-rel=\"lightbox-gallery-sKq9O1Ur\" data-rl_title=\"\" data-rl_caption=\"\" title=\"\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-869 aligncenter\" src=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1-300x193.png\" alt=\"Application r\u00e9sultat 1\" width=\"300\" height=\"193\" srcset=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1-300x193.png 300w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1-1024x658.png 1024w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1-768x493.png 768w, https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/appli-result-1.png 1118w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Pour aller plus loin on peut ajouter des facettes afin de filtrer plus finement la recherche, agr\u00e9menter Google Maps de photos de lieux etc. :)<\/p>\n<h2>Ressources int\u00e9ressantes :<\/h2>\n<ul>\n<li><a href=\"https:\/\/graphql.org\/learn\/queries\/\" target=\"_blank\" rel=\"noopener noreferrer\">Langage GraphQL<\/a><\/li>\n<li><a href=\"https:\/\/vuejs.org\/v2\/guide\/\" target=\"_blank\" rel=\"noopener noreferrer\">Documentation Vue.js<\/a><\/li>\n<li><a href=\"https:\/\/vue-apollo.netlify.com\/guide\/installation.html\" target=\"_blank\" rel=\"noopener noreferrer\">Apollo<\/a><\/li>\n<li><a href=\"https:\/\/hasura.io\/learn\/graphql\/hasura\/introduction\/\" target=\"_blank\" rel=\"noopener noreferrer\">Introduction \u00e0 Hasura<\/a><\/li>\n<li><a href=\"https:\/\/hasura.io\/learn\/graphql\/vue\/introduction\/\" target=\"_blank\" rel=\"noopener noreferrer\">Hasura avec Vue.js<\/a><\/li>\n<\/ul>\n<div style=\"padding-bottom:20px; padding-top:10px;\" class=\"hupso-share-buttons\"><!-- Hupso Share Buttons - https:\/\/www.hupso.com\/share\/ --><a class=\"hupso_counters\" href=\"https:\/\/www.hupso.com\/share\/\"><img decoding=\"async\" src=\"https:\/\/static.hupso.com\/share\/buttons\/dot.png\" style=\"border:0px; padding-top:2px; float:left;\" alt=\"Share Button\"\/><\/a><script type=\"text\/javascript\">var hupso_services_c=new Array(\"twitter\",\"facebook_like\",\"pinterest\",\"email\",\"linkedin\");var hupso_counters_lang = \"en_US\";var hupso_image_folder_url = \"\";var hupso_url_c=\"\";var hupso_title_c=\"D%C3%A9marrer%20avec%20Vue.js%2C%20Apollo%2C%20GraphQL%2C%20Hasura%20et%20PostgreSQL\";<\/script><script type=\"text\/javascript\" src=\"https:\/\/static.hupso.com\/share\/js\/counters.js\"><\/script><!-- Hupso Share Buttons --><\/div>","protected":false},"excerpt":{"rendered":"<p>Voici comment d\u00e9marrer tranquillement une application avec un front Vue.js qui interroge une API GraphQL. Le tout sans faire trop d&rsquo;effort \u00e0 l&rsquo;aide d&rsquo;Hasura et d&rsquo;Apollo. \u00c7a fait pas mal de technos : Vue.js : framework front JS Apollo : composant qui permet d\u2019interroger une API GraphQL depuis le front GraphQL : type d\u2019API cr\u00e9\u00e9 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[92,3,5],"tags":[90,60,88,91,59,89,87],"class_list":["post-828","post","type-post","status-publish","format-standard","hentry","category-api","category-data","category-javascript","tag-apollo","tag-docker","tag-graphql","tag-hasura","tag-javascript","tag-postgresql","tag-vue-js"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre<\/title>\n<meta name=\"description\" content=\"Application Vue.js avec une API GraphQL, \u00e0 l&#039;aide d&#039;Hasura et Apollo\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\" \/>\n<meta property=\"og:locale\" content=\"fr_FR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre\" \/>\n<meta property=\"og:description\" content=\"Application Vue.js avec une API GraphQL, \u00e0 l&#039;aide d&#039;Hasura et Apollo\" \/>\n<meta property=\"og:url\" content=\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\" \/>\n<meta property=\"og:site_name\" content=\"Melting Poutre\" \/>\n<meta property=\"article:published_time\" content=\"2020-03-16T21:58:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-03-05T21:21:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png\" \/>\n<meta name=\"author\" content=\"Louis Hatier\" \/>\n<meta name=\"twitter:label1\" content=\"\u00c9crit par\" \/>\n\t<meta name=\"twitter:data1\" content=\"Louis Hatier\" \/>\n\t<meta name=\"twitter:label2\" content=\"Dur\u00e9e de lecture estim\u00e9e\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\"},\"author\":{\"name\":\"Louis Hatier\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11\"},\"headline\":\"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL\",\"datePublished\":\"2020-03-16T21:58:00+00:00\",\"dateModified\":\"2021-03-05T21:21:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\"},\"wordCount\":891,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11\"},\"image\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png\",\"keywords\":[\"Apollo\",\"Docker\",\"GraphQL\",\"Hasura\",\"JavaScript\",\"PostgreSQL\",\"Vue.js\"],\"articleSection\":[\"API\",\"Data\",\"JavaScript\"],\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\",\"url\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\",\"name\":\"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre\",\"isPartOf\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png\",\"datePublished\":\"2020-03-16T21:58:00+00:00\",\"dateModified\":\"2021-03-05T21:21:34+00:00\",\"description\":\"Application Vue.js avec une API GraphQL, \u00e0 l'aide d'Hasura et Apollo\",\"inLanguage\":\"fr-FR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage\",\"url\":\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png\",\"contentUrl\":\"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png\",\"width\":450,\"height\":141,\"caption\":\"Vue.js, Apollo, GraphQL, Hasura, PostgreSQL\"},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/#website\",\"url\":\"https:\/\/louis.hatier.me\/blog\/\",\"name\":\"Melting Poutre\",\"description\":\"Du web et d&#039;autres choses\",\"publisher\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/louis.hatier.me\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"fr-FR\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11\",\"name\":\"Louis Hatier\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"fr-FR\",\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cd8d107ede5a4ec340326655e74a00ca62b02e41a02442f961c36f085aa89942?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cd8d107ede5a4ec340326655e74a00ca62b02e41a02442f961c36f085aa89942?s=96&d=mm&r=g\",\"caption\":\"Louis Hatier\"},\"logo\":{\"@id\":\"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/image\/\"},\"sameAs\":[\"https:\/\/louis.hatier.me\",\"https:\/\/www.linkedin.com\/in\/louishatier\/\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre","description":"Application Vue.js avec une API GraphQL, \u00e0 l'aide d'Hasura et Apollo","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/","og_locale":"fr_FR","og_type":"article","og_title":"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre","og_description":"Application Vue.js avec une API GraphQL, \u00e0 l'aide d'Hasura et Apollo","og_url":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/","og_site_name":"Melting Poutre","article_published_time":"2020-03-16T21:58:00+00:00","article_modified_time":"2021-03-05T21:21:34+00:00","og_image":[{"url":"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png","type":"","width":"","height":""}],"author":"Louis Hatier","twitter_misc":{"\u00c9crit par":"Louis Hatier","Dur\u00e9e de lecture estim\u00e9e":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#article","isPartOf":{"@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/"},"author":{"name":"Louis Hatier","@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11"},"headline":"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL","datePublished":"2020-03-16T21:58:00+00:00","dateModified":"2021-03-05T21:21:34+00:00","mainEntityOfPage":{"@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/"},"wordCount":891,"commentCount":0,"publisher":{"@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11"},"image":{"@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage"},"thumbnailUrl":"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png","keywords":["Apollo","Docker","GraphQL","Hasura","JavaScript","PostgreSQL","Vue.js"],"articleSection":["API","Data","JavaScript"],"inLanguage":"fr-FR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/","url":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/","name":"D\u00e9marrer avec Vue.js, Apollo, GraphQL, Hasura et PostgreSQL - Melting Poutre","isPartOf":{"@id":"https:\/\/louis.hatier.me\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage"},"image":{"@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage"},"thumbnailUrl":"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql-300x94.png","datePublished":"2020-03-16T21:58:00+00:00","dateModified":"2021-03-05T21:21:34+00:00","description":"Application Vue.js avec une API GraphQL, \u00e0 l'aide d'Hasura et Apollo","inLanguage":"fr-FR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/"]}]},{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/louis.hatier.me\/blog\/demarrer-avec-vue-js-apollo-graphql-hasura-et-postgresql\/#primaryimage","url":"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png","contentUrl":"https:\/\/louis.hatier.me\/blog\/wp-content\/uploads\/2020\/03\/vue-apollo-graphql-hasura-postgresql.png","width":450,"height":141,"caption":"Vue.js, Apollo, GraphQL, Hasura, PostgreSQL"},{"@type":"WebSite","@id":"https:\/\/louis.hatier.me\/blog\/#website","url":"https:\/\/louis.hatier.me\/blog\/","name":"Melting Poutre","description":"Du web et d&#039;autres choses","publisher":{"@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/louis.hatier.me\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"fr-FR"},{"@type":["Person","Organization"],"@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/2f200d0368def135b452e65491c4dd11","name":"Louis Hatier","image":{"@type":"ImageObject","inLanguage":"fr-FR","@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cd8d107ede5a4ec340326655e74a00ca62b02e41a02442f961c36f085aa89942?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cd8d107ede5a4ec340326655e74a00ca62b02e41a02442f961c36f085aa89942?s=96&d=mm&r=g","caption":"Louis Hatier"},"logo":{"@id":"https:\/\/louis.hatier.me\/blog\/#\/schema\/person\/image\/"},"sameAs":["https:\/\/louis.hatier.me","https:\/\/www.linkedin.com\/in\/louishatier\/"]}]}},"_links":{"self":[{"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/posts\/828","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/comments?post=828"}],"version-history":[{"count":39,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/posts\/828\/revisions"}],"predecessor-version":[{"id":885,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/posts\/828\/revisions\/885"}],"wp:attachment":[{"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/media?parent=828"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/categories?post=828"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/louis.hatier.me\/blog\/wp-json\/wp\/v2\/tags?post=828"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}