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
IAM
on the navigation bar on the left, and add thecloud build
andcloud run
permissions to the<project-number>-compute@developer.gserviceaccount.com
- Go to service accounts and under
actions
create 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 login
and login with the same account used to create the project - Type
gcloud config set project <project-id>
- Then, modify the provided
cloudbuild.yaml
file 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.