Full Stack Integration Workshop
Prerequisites
For this workshop you will need the following programs installed:
- Node.js: Install Node LTS from here
- Yarn: Follow the instructions here (we will use yarn over npm)
- Flask: in terminal run
pip install flask - Google Cloud CLI: Select your operating system here and follow directions in
Before you begin. - Firebase: Create an account on Firebase
Deployment
To deploy your web application means to put it on a Web server so others can access it via the internet. We will be demonstrating how to deploy your projects (both frontend and backend) using Firebase.
note
Wait, what is Firebase?
Firebase is a platform built by Google which consists of authentication, hosting, file storage, cloud functions, a realtime NoSQL database, and more. You can learn more about its features at firebase.google.com
Backend Deployment
We will be deploying our backend Flask app on Google Cloud Run. For the backend, we will be using the following sample Flask endpoint (refer to the backend workshop for more info):
from flask import Flask, request, jsonify
app = Flask(__name__)
# All the products we are selling
PRODUCTS = [
{ 'category': 'Sporting Goods', 'price': '$49.99', 'stocked': True, 'name': 'Football' },
{ 'category': 'Sporting Goods', 'price': '$9.99', 'stocked': True, 'name': 'Baseball' },
{ 'category': 'Sporting Goods', 'price': '$29.99', 'stocked': False, 'name': 'Basketball' },
{ 'category': 'Electronics', 'price': '$999.99', 'stocked': True, 'name': 'iPad Pro' },
{ 'category': 'Electronics', 'price': '$399.99', 'stocked': False, 'name': 'iPhone 5' },
{ 'category': 'Electronics', 'price': '$199.99', 'stocked': True, 'name': 'Nexus 7' }
]
# endpoint to handle GET requests at /products, we will return all the entries in PRODUCTS
@app.route('/products')
def get_all_products():
return jsonify({'products': PRODUCTS})
if __name__ == '__main__':
app.run(threaded=True, host='0.0.0.0', port=8080)
Firebase Setup
- Navigate to Firebase and create a new project
- Initialize cloud storage and firestore
- Enable billing β it wonβt actually charge you
- Navigate to Google Cloud Platform search for
Cloud Run API, and enable it - Go to
IAMon the navigation bar on the left, and add thecloud buildandcloud runpermissions to the<project-number>-compute@developer.gserviceaccount.com - Go to service accounts and under
actionscreate a new key for the same account β move this file to your project directory and name itkey.json
Deployment Process
- First, you should have downloaded the gcloud command line interface (CLI) as per the pre-requisites
- In your project directory, type
gcloud auth loginand login with the same account used to create the project - Type
gcloud config set project <project-id> - Then, modify the provided
cloudbuild.yamlfile to use your project name in place of ours, and your developer account email instead of ours - Run
gcloud builds submit --config cloudbuild.yaml .
You should get a link like https://todo-RANDOMHASH-uc.a.run.app/products. Copy/save this outputted URL because you will using this in the frontend API call.
Frontend Deployment
Example Code
For the frontend, we used the example code here taken from React docs here, but instead of declaring all the products in the App component, we make a GET call to our backend /products endpoint in the FilterableProductTable to fetch the products list. The relevant changes are below:
note
import React from 'react';
import FilterableProductTable from './FilterableProductTable';
const App = () => (
<div className="App">
<FilterableProductTable />
</div>
);
export default App;
import React from 'react';
const FilterableProductTable = () => {
const [products, setProducts] = useState([]);
const [filterText, setFilterText] = useState('');
const [inStockOnly, setInStockOnly] = useState(false);
const handleFilterTextChange = (e) => setFilterText(e.target.value);
const handleCheckBoxChange = (e) => setInStockOnly(e.target.checked);
// this function fetches the products data from our backend endpoint
useEffect(() => {
// add the BACKEND_URL you received from deploying your backend
fetch('[BACKEND_URL]/products')
.then((resp) => resp.json())
.then(({ products }) => setProducts(products));
}, []);
return (
<div>
<SearchBar
filterText={filterText}
inStockOnly={inStockOnly}
handleFilterTextChange={handleFilterTextChange}
handleCheckBoxChange={handleCheckBoxChange}
/>
<ProductTable
products={products}
filterText={filterText}
inStockOnly={inStockOnly}
/>
</div>
);
};
export default FilterableProductTable;
tip
In testing, we can add this line to package.json to proxy our requests to a locally deployed backend:
"proxy": "http://localhost:8080",
The port is 8080 because our backend is running on port 8080 of localhost (equivalently, 0.0.0.0).
Deployment Process
To deploy frontend to Firebase enter the following commands into terminal:
yarn global add firebase-tools
yarn build
firebase login
firebase init
<answer the questions>
firebase deploy
yarn build will create a build directory containing a production build of your application.
firebase login will prompt you to log in by opening up a web browser if you're not already signed it.
firebase init will ask you the following questions:
- Which Firebase CLI features do you want to set up for this folder? Select Hosting.
- Associate with a Firebase project. Select your Firebase project
- What do you want as your public directory? build
- Configure as a single-page app (rewrite all urls to /index.html)? Yes
- Overwrite
index.html? No
Running firebase deploy will push your build assets to Firebase remote server and give you a URL to your live Firebase app site! Now you can share this site and access it over the internet.