# Requêtes HTTP
# Architecture
Dans une Single Page Application (SPA), la communication avec le serveur se fait via des requêtes HTTP asynchrones (AJAX) ou des protocoles plus spécialisés comme les WebSocket. Nous allons voir comment faire ces requêtes réseau depuis une application Vue.
Vue.js est un framework qui se focalise sur l'interface utilisateur et ne propose rien de particulier en ce qui concerne les échanges avec le serveur, préférant laisser ce choix d'implémentation au développeur. Le moyen le plus simple de lancer une requête HTTP asynchrone en JavaScript est d'utiliser la méthode fetch
(opens new window). Elle n'est pas supportée sur Internet Explorer mais il existe des polyfills pour compléter le support. Comme alternative, vous pouvez passer par d'autres bibliothèques tierces plus complètes telles que Axios (opens new window), qui est recommandée par l'équipe de Vue.
TIP
On évitera de faire les appels réseau directement depuis le code d'un composant. Cela empêche de réutiliser le code facilement si un autre composant doit faire le même appel. Optez plutôt pour systématiquement séparer la logique applicative de la logique de vos vues.
Par convention, on code la logique applicative dans des fichiers JS appelés services, répartis selon les grands pans fonctionnels de votre application et placés dans un dossier src/services
# TP : Échanger avec un back-end
Nous allons nous servir d'une API fournie par un serveur (le back-end) pour authentifier les utilisateurs et rechercher des films. Ce back-end a déjà été développé, vous pouvez clôner le repo (opens new window) et lancer l'API localement avec:
git clone https://github.com/worldline/vuejs-training-backend
cd ./vuejs-training-backend/
npm install
npm start
Une clé d'API OMDB vous sera demandée pour pouvoir effectuer des recherches de films. Vous pouvez en obtenir une ici (opens new window).
TIP
Une fois le serveur démarré, le contrat d'interface du back-end est disponible ici : api-docs (opens new window)
- Créer un service générique
services/api.js
permettant d'appeler le backend, avec ce contenu :
import { useSession } from '../stores/session.js'
export const BASE_URL = 'http://localhost:3030'
export async function api (url, params = {}) {
const session = useSession()
params = Object.assign({
mode: 'cors',
cache: 'no-cache',
}, params)
params.headers = Object.assign({
Authorization: `Bearer ${session.token}`,
'Content-Type': 'application/json'
}, params.headers)
let response = await fetch(BASE_URL + url, params)
let json = await response.json() || {}
if (!response.ok){
let errorMessage = json.error || response.status
throw new Error(errorMessage)
}
return json
}
Il n'y a pas de code spécifique à Vue ici, il s'agit d'une fonction utilitaire autour de la méthode fetch
branchée sur notre back-end. Le header Authorization
est utilisé pour envoyer le token d'authentification au back-end. Les autres options servent à configurer le cache HTTP et les autorisations cross-origin à appliquer.
- Créer un service
services/UserService.js
qui exploitera les endpoints de l'API concernant l'inscription et le login des utilisateurs :
import { api } from '@/services/api.js'
export default {
register (credentials) {
return api('/user/register', {
method: 'POST',
body: JSON.stringify(credentials)
})
},
login (credentials) {
return api('/user/login', {
method: 'POST',
body: JSON.stringify(credentials)
})
}
}
- Dans le composant
LoginForm
, ajoutez un second bouton pour s'inscrire à côté de celui pour se login, puis modifiez les méthodes deLoginForm
pour appeler les méthodes duUserService
:
import UserService from '@/services/UserService.js'
export default {
methods: {
async register () {
this.error = null;
try {
const response = await UserService.register({
email: this.email,
password: this.password,
firstname: 'John',
lastname: 'Smith'
})
const session = useSession();
session.login({ user: response.user, token: response.token });
this.$router.push('/search')
} catch (error) {
this.error = error.toString()
}
},
async login () {
this.error = null;
try {
const response = await UserService.login({ email: this.email, password: this.password })
const session = useSession();
session.login({ user: response.user, token: response.token });
this.$router.push('/search')
} catch (error) {
this.error = error.toString()
}
}
}
}
Notez qu'en cas d'erreur, on stocke le message d'erreur retourné dans une variable
error
. Si ce n'est pas déjà fait, déclarez cette variable dans lesdata
du composant et utilisez-là dans le template pour afficher le message d'erreur en cas d'échec d'authentification.Notez également que la réponse du back-end au login contient un token permettant d'authentifier l'utilisateur, qui est transmis au store dans les paramètres de l'action
login
. Modifiezstores/session.js
pour stocker cetoken
dans le store.Le service
api
est déjà configuré pour ajouter ce token en headerAuthorization
des requêtes. Vérifiez que le token est bien envoyé en header HTTP via les outils développeur de votre navigateur.Bonus : Modifier l'action
logout
du store pour supprimer le token et les infos utilisateur du store à la déconnexion, et assurez-vous que l'utilisateur est bien redirigé vers le formulaire de login.Créez un service
FilmService
avec une méthode pour rechercher les films, en suivant la documentation de l'API (GET /movies/search
).Complétez le composant
SearchFilm
avec une dataquery
liée au formulaire de recherche, puis appelezFilmService
afin de permettre à l'utilisateur de chercher un film par son nom.
TIP
Si vous avez découvert qu'il existait un film appelé Undefined, c'est que vous vous êtes trompés quelque-part 😃