Integrating Vue.js with Serverless Order Processing in GCP
Introduction
In the previous tutorial, we developed a serverless order processing system on Google Cloud using API Gateway, Cloud Functions, Firestore, and Cloud Tasks. This backend system handles order placement, background processing, and logging.
In this tutorial, we’ll extend our system by integrating a client user interface (UI) using Vue.js. Vue.js is a progressive JavaScript framework for building user interfaces and single-page applications. We will focus on:
- Setting up a Vue.js project.
- Building components for order creation and displaying order status.
- Integrating Firebase Cloud Messaging (FCM) for real-time push notifications.
Setting Up Firebase Cloud Messaging (FCM)
To begin with Firebase Cloud Messaging (FCM), we first need to create a Firebase project. This project will serve as the foundation for integrating FCM into our web application.
Go to the Firebase Console and log in with your Google account. If you haven’t created a Firebase project yet, you’ll need to start by setting up a new Firebase project:
- Click on the “Create a project” button or select an existing project from the Firebase Console dashboard.
- Follow the prompts to give your project a name. Optionally, you can enable Google Analytics for your project, which provides insights into user engagement and app usage.
- After creating the Firebase project, click on the project name to enter the project dashboard.
- Click on the “Add App” and then click on the “Web” icon () to add Firebase to your web app.
- Provide a nickname for your app (e.g., “MyOrderApp”) and click “Register app”.
Once registered, Firebase will provide you with a configuration object containing API keys and other identifiers essential for connecting your web app to Firebase services. This configuration looks something like this:
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
const firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "orderprocessingsystem.firebaseapp.com",
projectId: "orderprocessingsystem",
storageBucket: "orderprocessingsystem.appspot.com",
messagingSenderId: "244205369552",
appId: "1:244205369552:web:73c966048159c84bdb06d5"
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
Copy this configuration as you’ll need it when integrating Firebase into your Vue.js application.
In the Firebase Console, click on “Settings” (the gear icon) next to “Project Overview”. Select “Project settings”, then navigate to the “Cloud Messaging” tab.
Under “Web configuration”, if you haven’t already set up credentials, Firebase will guide you through generating a new key pair (VAPID key). This key pair is necessary for secure communication and sending push notifications to your web application.
Setting Up Vue.js Project
To begin, we need to set up a Vue.js project and integrate Firebase for handling notifications. Firstly, if Vue CLI is not already installed, we’ll need to do so using npm (Node Package Manager):
npm install -g @vue/cli
Next, create a new Vue project named order-processing-system
:
vue create order-processing-system
Follow the prompts to select features and configure your Vue project according to your requirements. After setting up the Vue project, we need to add Firebase SDK to enable Firebase services:
cd order-processing-system
npm install firebase
To connect our Vue.js project to Firebase, we create a firebaseConfig
object containing essential credentials and settings. This configuration initializes Firebase and configures Firebase Messaging (firebase.messaging()
), allowing us to handle notifications.
import firebase from "firebase/compat/app";
import "firebase/compat/messaging";
const firebaseConfig = {
apiKey: "AIzaSyB4AizQm5pmnP1GozUJqHlKE3Zp5H9MfpI",
authDomain: "orderprocessingsystem.firebaseapp.com",
projectId: "orderprocessingsystem",
storageBucket: "orderprocessingsystem.appspot.com",
messagingSenderId: "244205369552",
appId: "1:244205369552:web:73c966048159c84bdb06d5"
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
export { messaging };
By exporting messaging
, we make it accessible throughout our Vue.js application, enabling us to send notifications using Firebase Cloud Messaging (FCM) when specific events, such as order processing, occur.
Building Vue.js Components
Next, we will create two Vue components: OrderForm.vue
for order creation and OrderStatus.vue
for displaying the order status.
Creating the OrderForm Component
This component provides a form for users to place orders. When the form is submitted, it sends the order data to a specified API endpoint.
<!-- src/components/OrderFORM.vue -->
<template>
<div>
<form @submit.prevent="placeOrder">
<label for="order_id">Order ID:</label>
<input type="text" id="order_id" v-model="order.order_id" required><br><br>
<label for="product">Product:</label>
<input type="text" id="product" v-model="order.product" required><br><br>
<label for="quantity">Quantity:</label>
<input type="number" id="quantity" v-model.number="order.quantity" required><br><br>
<label for="customer_name">Customer Name:</label>
<input type="text" id="customer_name" v-model="order.customer_name" required><br><br>
<label for="customer_email">Customer Email:</label>
<input type="email" id="customer_email" v-model="order.customer_email" required><br><br>
<label for="status">Status:</label>
<select id="status" v-model="order.status" required>
<option value="Pending">Pending</option>
<option value="Processing">Processing</option>
<option value="Completed">Completed</option>
</select><br><br>
<button type="submit">Place Order</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
order: {
order_id: '',
product: '',
quantity: null,
customer_name: '',
customer_email: '',
status: 'Pending'
}
};
},
methods: {
async placeOrder() {
try {
fetch('https://asia-southeast1-orderprocessingsystem.cloudfunctions.net/createOrder', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(this.order)
})
.then(response => {
return response.json();
})
.then(data => {
console.log("Order placed:", data);
})
.catch(error => {
console.error('Error placing order:', error);
});
} catch (error) {
console.error('Error placing order:', error);
alert('Failed to place order. Please try again.');
}
}
}
};
</script>
Creating the OrderStatus Component
This component listens for FCM notifications and updates the order status accordingly.
<!-- src/components/OrderStatus.vue -->
<template>
<div>
<h2>Order Status</h2>
<p v-if="loading">Loading order status...</p>
<p v-else>{{ status }}</p>
</div>
</template>
<script>
import { messaging } from '../firebase';
export default {
data() {
return {
status: '',
loading: true
};
},
created() {
// Example: Subscribe to Firebase Cloud Messaging (FCM) notifications
messaging.onMessage(payload => {
console.log('FCM Message received:', payload);
this.loading = false;
this.status = `Order ${payload.data.orderId} processed`;
});
}
};
</script>
Using Components in the Main App
We will now integrate the OrderForm
and OrderStatus
components into our main application component, App.vue
.
<!-- src/App.vue -->
<template>
<div id="app">
<h1>Order Processing System</h1>
<OrderForm />
<OrderStatus />
</div>
</template>
<script>
import OrderForm from './components/OrderForm.vue';
import OrderStatus from './components/OrderStatus.vue';
export default {
components: {
OrderForm,
OrderStatus
}
};
</script>
Firebase Cloud Messaging (FCM) Integration
To complete the FCM integration, we need to handle incoming messages using a service worker. We’ll create a service worker file and register it in our Vue.js project.
Create the Service Worker File
First, create a service worker file named firebase-messaging-sw.js
in the public
directory of your Vue project. This file is responsible for handling incoming FCM messages, especially when the app is not in the foreground. This ensures that users receive notifications even when they are not actively using the app.
// public/firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/10.1.0/firebase-app-compat.js')
importScripts('https://www.gstatic.com/firebasejs/10.1.0/firebase-messaging-compat.js')
const firebaseConfig = {
apiKey: "AIzaSyB4AizQm5pmnP1GozUJqHlKE3Zp5H9MfpI",
authDomain: "orderprocessingsystem.firebaseapp.com",
projectId: "orderprocessingsystem",
messagingSenderId: "244205369552",
appId: "1:244205369552:web:73c966048159c84bdb06d5"
};
firebase.initializeApp(firebaseConfig);
const messaging = firebase.messaging();
messaging.onBackgroundMessage((payload) => {
console.log('FCM Background Message received:', payload);
const notificationTitle = payload.notification.title;
const notificationOptions = {
body: payload.notification.body,
icon: payload.notification.icon
};
return self.registration.showNotification(notificationTitle, notificationOptions);
});
We handle background messages with messaging.onBackgroundMessage
, displaying a notification when an FCM message is received while the app is in the background.
Register the Service Worker
Next, we need to register this service worker in our main application file, typically main.js
or index.js
. This service worker listens for background messages and displays notifications using the self.registration.showNotification
method. This improves user engagement by ensuring they are notified of important updates.
// src/main.js
import { createApp } from 'vue';
import App from './App.vue';
import { messaging } from './firebase';
navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then((registration) => {
console.log('Service Worker registered:', registration);
console.log(messaging)
messaging.getToken({ vapidKey: 'YOUR_PUBLIC_VAPID_KEY' })
.then((currentToken) => {
if (currentToken) {
console.log('Firebase Token:', currentToken);
// Send the token to your server for storing and sending notifications
fetch('https://asia-southeast1-orderprocessingsystem.cloudfunctions.net/storeToken', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
token: currentToken,
user_id: 'USER_ID' // Replace with actual user ID or identifier
})
})
.then(response => {
console.log(response);
if (!response.ok) {
throw new Error('Failed to store token on server');
}
return response.json();
})
.then(data => {
console.log('Token stored successfully:', data);
})
.catch(error => {
console.error('Error storing token:', error);
});
} else {
console.log('No registration token available. Request permission to generate one.');
}
}).catch((err) => {
console.log('An error occurred while retrieving token. ', err);
});
}).catch((err) => {
console.error('Service Worker registration failed:', err);
});
createApp(App).mount('#app');
The VAPID key ('YOUR_PUBLIC_VAPID_KEY'
) is used to authorize requests to FCM.
When the service worker is registered, we obtain the FCM token using messaging.getToken
. We send this token to our backend endpoint (https://YOUR_API_GATEWAY_URL/storeToken
) to be stored along with user information. With the token, we can send Firebase Cloud Messaging (FCM) notifications to specific users.
With these components in place, our Vue.js application can now handle order creation and display order status updates in real time:
- OrderForm Component: This component allows users to place orders by submitting item details and quantity. It handles form submission and communicates with the backend API.
- OrderStatus Component: This component listens for FCM notifications and updates the user interface with the latest order status. It provides real-time feedback to users as their orders are processed.
- Main App Integration: By integrating these components into
App.vue
, we create a cohesive user interface for managing and tracking orders within our application.
Create a Function to store Token
Let’s create a Cloud Function to store the FCM tokens when users register for notifications. This Cloud Function will accept the token and user ID from the client side and store them in Firestore.
import firebase_admin
from firebase_admin import credentials, firestore
from flask import jsonify, request
# Initialize Firebase Admin SDK
cred = credentials.ApplicationDefault()
firebase_admin.initialize_app(cred, {
'projectId': 'orderprocessingsystem',
})
db = firestore.client()
def store_token(request):
try:
request_json = request.get_json()
token = request_json.get('token')
user_id = request_json.get('user_id')
if not token or not user_id:
return jsonify({'error': 'Invalid request'}), 400
docs = db.collection('fcmTokens').where('user_id', '==', user_id).limit(1).get()
if docs:
doc_id = docs[0].id
db.collection('fcmTokens').document(doc_id).update({
'token': token
})
return jsonify({'message': 'Token stored successfully'}), 200
else:
db.collection('fcmTokens').add({
'token': token,
'user_id': user_id
})
return jsonify({'message': 'Token stored successfully'}), 200
return jsonify({'message': 'Token stored successfully'}), 200
except Exception as e:
print(f"Error storing token: {e}")
return jsonify({'error': 'Internal Server Error'}), 500
Update processOrder
Function to Include FCM Notification
We’ll need to modify our existing code to include the logic for sending FCM notifications when an order is processed. Here’s how we can achieve this:
def process_order(request):
try:
...
# Simulate processing delay
time.sleep(5) # Simulate processing taking 5 seconds
# Send FCM notification
send_fcm_notification(order_id, "USER_ID") // for demostrating purpose.
...
def send_fcm_notification(order_id, user_id):
# Retrieve the FCM token from Firestore
docs = db.collection('fcmTokens').where('user_id', '==', user_id).limit(1).get()
if not docs:
print('No FCM token found for user_id:', user_id)
return
fcm_token = docs[0].to_dict().get('token')
if not fcm_token:
print('FCM token is missing for user_id:', user_id)
return
# Get a reference to the Firebase Cloud Messaging service
message = messaging.Message(
data={
'orderId': order_id,
'status': 'processed'
},
notification=messaging.Notification(
title='Order Processed',
body=f'Your order {order_id} has been processed successfully.'
),
token=fcm_token
)
# Send the notification
response = messaging.send(message)
print('Successfully sent FCM notification:', response)
Test and Verify
Let’s test and verify our application to ensure we can receive the notification instantly. Start the development server by running:
npm run serve
The application should now be running at http://localhost:8080
.
Fill out the order form with the necessary details. For example, we might need to enter the order ID, customer details, and other relevant information.
Click the “Submit Order” button to submit the order. This action will trigger a request to the backend to create the order and process it.
After submitting the order, observe the OrderStatus
component is displayed. Initially, it will show “Loading order status…”. Wait for the backend to process the order. This may take a few seconds due to the simulated delay in the process_order
function.
Once the order is processed, the OrderStatus
component should update and display the message indicating that the order has been processed, such as “Order [orderId] processed”.
Conclusion
In this tutorial, we explored how to integrate Vue.js with our existing serverless order processing system on Google Cloud. We covered setting up a Vue project, building components for order creation and status display, and integrating Firebase Cloud Messaging (FCM) for real-time notifications. Full source code is available on GitHub.
Share this content:
Leave a Comment