# HTTP Requests
# Architecture
In a Single Page Application (SPA), communication with the server is done via asynchronous HTTP requests (AJAX) or more specialized protocols such as WebSocket. We will see how to make these network requests from a Vue application.
Vue.js is a framework that focuses on the user interface and offers nothing special to exchanges with a server. This choice of implementation is left to the developer. The easiest way to make an asynchronous HTTP request in JavaScript is to use the fetch
method (opens new window). It is not supported on Internet Explorer but there are polyfills to complete the support. As an alternative, you can use other more complete third-party libraries such as Axios (opens new window), which is recommended by the Vue team.
TIP
Network calls should not be done directly from the code of a component. This prevents reuse of the code easily if another component has to make the same call. Instead, opt to systematically separate the application logic from the logic of your views.
By convention, we code the application logic in JS files called services, distributed according to the large functional parts of your application and placed in a folder src/services
.
# Practical Work: Communicate with a back-end
We will use a server-provided API (the back-end) to authenticate users and search for films. This back-end has already been developed, you can clone this repo (opens new window) and run the API locally with:
git clone https://github.com/worldline/vuejs-training-backend
cd ./vuejs-training-backend/
npm install
npm run start
An OMDB API key will be required to search for films. You can get one here (opens new window).
TIP
Once the server has started, The back-end interface contract is available here: api-docs (opens new window)
- Create a generic service (
services/api.js
) to call the backend, with this content:
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;
}
There is no code specific to Vue here, it is a utility function around the fetch
method to communicate with our backend. The Authorization
header is used to send the authentication token to the backend. Other options are used to configure HTTP caching and the cross-origin permissions to apply.
- Create a
services/UserService.js
service that will use API endpoints for user registration and login:
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),
});
},
user() {
return api("/user");
},
};
- In
LoginForm
component, add a second button to register next to the login button, then modify theLoginForm
methods to call the functions located inUserService
:
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();
}
},
},
};
Note that in the event of an error, the error message is stored in an
error
variable. If not already done, declare this variable in the component'sdata
and use it in the template to display the error message in case of authentication failure.Note also that the response of the back-end after login contains a token to authenticate the user, which is passed to the store in the parameters of the
login
action. Modifystores/session.js
to also store thistoken
.The
api
service is already configured to add this token to the request authorization header. Check that the token is sent as a HTTP header via the developer tools of your browser.Bonus: Modify the store's logout action to remove the token and user info from the store upon logout, and make sure the user is redirected to the login form.
Create a
FilmService
service with a method to search for films, following the API documentation (GET /movies/search
).Complete the
SearchFilm
component with aquery
data bound to the search input, then call theFilmService
so that the user can search for a film by name.
TIP
If you discovered that there was a film called Undefined, then you made a mistake somewhere 😃
← Routing Unit tests →