Vue 03
Using Rest API
Install Axios
npm install axios
Axios is a promise-based HTTP Client for node.js and the browser. It is isomorphic (= it can run in the browser and nodejs with the same codebase). On the server-side it uses the native node.js http module, while on the client (browser) it uses XMLHttpRequests.
Example GET request
const axios = require('axios');
// Make a request for a user with a given ID
axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.finally(function () {
// always executed
});
// Optionally the request above could also be done as
axios.get('/user', {
params: {
ID: 12345
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
})
.finally(function () {
// always executed
});
// Want to use async/await? Add the `async` keyword to your outer function/method.
async function getUser() {
try {
const response = await axios.get('/user?ID=12345');
console.log(response);
} catch (error) {
console.error(error);
}
}
Axios based simple service
import Axios from 'axios';
import { IGpsSession } from '../domain/IGpsSession';
export abstract class GpsSessionsApi {
private static axios = Axios.create(
{
baseURL: "https://sportmap.akaver.com/api/v1.0/GpsSessions/",
headers: {
common: {
'Content-Type': 'application/json'
}
}
}
)
static async getAll(): Promise<IGpsSession[]> {
const url = "";
try {
const response = await this.axios.get<IGpsSession[]>(url);
console.log('getAll response', response);
if (response.status === 200) {
return response.data;
}
return [];
} catch (error) {
console.log('error: ', (error as Error).message);
return [];
}
}
}
Use generics
export interface IResultObject<TResponseData> {
errors?: string[]
data?: TResponseData
}
export interface IUserInfo {
"token": string,
"refreshToken": string,
"firstName": string,
"lastName": string
}
export type stringOrNull = string | null;
Login service
import type { IResultObject } from "@/types/IResultObject";
import type { IUserInfo } from "@/types/IUserInfo";
import axios from "axios";
export default class AccountService {
private constructor() {
}
private static httpClient = axios.create({
baseURL: 'https://taltech.akaver.com/api/v1/account/',
});
static async loginAsync(email: string, pwd: string): Promise<IResultObject<IUserInfo>> {
const loginData = {
email: email,
password: pwd
}
try {
const response = await AccountService.httpClient.post<IUserInfo>("login", loginData);
if (response.status < 300) {
return {
data: response.data
}
}
return {
errors: [response.status.toString() + " " + response.statusText]
}
} catch (error: any) {
return {
errors: [JSON.stringify(error)]
};
}
}
}
Store for auth
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
import type { stringOrNull } from '@/types/types'
export const useAuthStore = defineStore('auth', () => {
// ref - state variables
const jwt = ref<stringOrNull>(null)
const refreshToken = ref<stringOrNull>(null)
const userName = ref<stringOrNull>(null)
// computed - getters
const isAuthenticated = computed<boolean>(() => !!jwt.value);
// functions - actions
// return your refs, computeds and functions
return { jwt, refreshToken, userName, isAuthenticated }
})
Login view
<script setup lang="ts">
import AccountService from '@/services/AccountService';
import { useAuthStore } from '@/stores/auth';
import { ref } from 'vue';
const authStore = useAuthStore();
let loginName = ref('');
let loginPassword = ref('');
let loginIsOngoing = ref(false);
let errors = ref<string[]>([]);
const doLogin = async () => {
loginIsOngoing.value = true;
const res = await AccountService.loginAsync(loginName.value, loginPassword.value);
if (res.data) {
authStore.jwt = res.data.token;
authStore.refreshToken = res.data.refreshToken;
authStore.userName = res.data.firstName + ' ' + res.data.lastName;
errors.value = [];
} else {
errors.value = res.errors!;
}
loginIsOngoing.value = false;
}
</script>
<template>
<h1>Log in</h1>
<div class="row">
<div class="col-md-6">
<section>
<form id="account" method="post">
<hr />
<div>{{ errors.join(',') }}</div>
<div class="form-floating mb-3">
<input v-model="loginName" class="form-control" autocomplete="username" aria-required="true"
placeholder="name@example.com" type="email" id="Input_Email" name="Input.Email" value="" />
<label class="form-label" for="Input_Email">Email</label>
</div>
<div class="form-floating mb-3">
<input v-model="loginPassword" class="form-control" autocomplete="current-password"
aria-required="true" placeholder="password" type="password" id="Input_Password"
name="Input.Password" />
<label class="form-label" for="Input_Password">Password</label>
</div>
<div>
<button @click.prevent="doLogin" id="login-submit" type="submit"
class="w-100 btn btn-lg btn-primary">{{ loginIsOngoing ? 'Wait...' : 'Do login' }}</button>
</div>
</form>
</section>
</div>
</div>
</template>
<style scoped></style>