civisanalytics/civis-services-flask-demo
Example Flask app hosted in Civis
40
This repository shows you how to host a web application in Civis Platform. The example provided here is a simple Flask app. This app queries the service for data in JSON format to display on the page.
To host your modified service on Civis Platform, you will need a Github account. See this article in the Civis Help Center if you have not yet connected your Github account to Civis.
To make changes to and run this application, you will need git
and Docker installed on your machine. Civis uses Docker to host web applications, so using Docker locally is the most reliable way to develop and troubleshoot your application. You can follow the instructions here to install Docker on your machine.
First, let's run this Github repo (the one you are reading right now) as a service in Civis.
https://github.com/civisanalytics/civis-services-flask-demo.git
main
civisanalytics/civis-services-flask-demo
Start Deployment
to run the service.Once the service has started up, you should see a "Your service is running!" message in the preview window. You can also view the logs for the service by clicking Deployment History
.
Click Stop Deployment
to shut down the service and stop using compute resources. If you forget to shut down the service, it will sleep automatically after one hour of inactivity.
Next, let's run the service on your own machine.
docker-compose up --build -V
.CTRL-C
to stop the web server.Every time you make a change to the code, you should stop docker-compose
and start it again. Subsequent runs will start up much faster.
You might have noticed one or two differences between the applications running in Civis and locally. Applications running in Civis have an API key automatically provided in the CIVIS_API_KEY
environment variable. This Flask app uses that key to retrieve the username of the owner of the service. If the last item in the response has name: null
then you don't have this variable set locally. This is normal.
We recommend setting this value in a .env
file. docker-compose
will automatically read this file and it will be ignored by git
.
.env
file in the same directory as this README..env
file with:
CIVIS_API_KEY=<the API key you just generated>
You should now see your Civis username on the page.
The API response from the service includes an is_favorite
attribute for each of the fruits, but the value should be false
for every fruit. The app can be configured with a favorite fruit using a different environment variable.
First, we'll set this variable locally.
.env
file with:
FLASK_DEMO_FAVORITE_FRUIT_PASSWORD=<your choice of: Strawberry, Watermelon, Grapefruit, or your username>
CTRL-C
to stop it and then docker-compose up --build -V
to restart it)You should now see that the fruit you selected is marked as a favorite!
Next, we'll configure the service running in Civis to receive this environment variable. To do this, we will first create a Civis Credential and then attach that credential to the service.
Create Credential
Flask Demo Favorite Fruit
Custom
fruit
(for this example the username will not be used)Save
Flask Demo Favorite Fruit
credential. This will make the username and password of the credential available to the service through environment variables.Start Deployment
to start the service. If the service is still running from the last time you started it, click Stop Deployment
and wait for the page to update, then click Start Deployment
to restart it.You should again see that the fruit you selected is marked as a favorite! If not, try refreshing the page to make sure you are not looking at an old version of the service.
You should now be comfortable running the service locally and in Civis Platform. To make further changes, fork this Github repo into your own account and create a new service in Civis connected to your forked repo. As you push changes to Github, you will see them reflected in the service when you stop and restart it.
Instead of clicking Stop Deployment
, you could instead click on Update Deployment
. This will redeploy your service with no downtime, i.e., your old application will still be available while your new version is starting up. This is a great option for your production applications, but during development it can be unclear whether you are looking at an old or new version of the app. We recommend stopping and starting the service while testing out changes.
If you would like to upgrade your packages or install new packages, please add to the requirements.txt
file at the root of this repo. You can also modify the start_service.sh
script if you need to install libraries or more complex dependencies.
In Platform, the CIVIS_API_KEY
variable belongs to the user who owns the service, not the user making the request to the service. Be careful about making requests on behalf of users, as this might pose a security risk.
This example application does not attempt to set up a fully featured front end. It uses a simple HTML and Javascript file. The frontend lives in the dist
folder. The index.html
file uses main.js
to call the /fruits
endpoint and update the page.
You can use React, Angular, or any other Javascript framework in your service. Just make sure that your root API endpoint (/) returns the initial landing page for your app. If not, Platform will consider your app to be down and continuously attempt to restart it.
NOTE: Browsers will often cache HTML and Javascript files by name. Therefore, we recommend having the Javascript file(s) named using a commit hash or similar to prevent caching.
You can access your service's API easily using a Civis API key. All applications running in Civis are automatically provided with an API key, so you can use this key to access a running service without needing an additional authentication token. To provide or revoke access to the service, click Share
on the service page to modify permissions.
In the example below, we will hit the API of a Platform service from a Platform notebook. Make sure your service is running before trying out this example. In production code, you would want to catch this sort of error, deal with timeouts, etc.
Go to https://platform.civisanalytics.com/spa/#/notebooks/new?language=python3 and click Start Server
to start up a new Jupyter notebook.
Direct access to the service expires after five minutes. We recommend using the cachetools
package to re-authenticate with the service every 2 minutes. Run the following code in your notebook:
!pip install cachetools
In the next cell, store your service ID in a variable so it can be reused:
SERVICE_ID = <your service ID>
Now add code for making an authenticated request to the service:
import requests
import cachetools.func
@cachetools.func.ttl_cache(ttl=120)
def _service_session(service_id):
session = requests.Session()
service = client.services.get(service_id)
auth_url = service['current_deployment']['displayUrl']
base_url = service['current_url']
session.get(auth_url)
return [session, base_url]
def service_request(service_id, endpoint):
session, base_url = _service_session(service_id)
resp = session.get(base_url + endpoint)
return resp
You should now be able to access the API for the service:
service_request(SERVICE_ID, "/api/health").text
should return the result:
'The ID of this service is: ...'
The fruits API endpoint:
service_request(SERVICE_ID, "/api/fruits/").json()
should match the result shown on the service page.
You can also access your service's API from outside of Platform. This is not recommended, but sometimes necessary to allow access from other systems.
In order to do this, you must generate a service token for your service. See https://civis.zendesk.com/hc/en-us/articles/360004026012-Advanced-Deployments#ServiceTokenAuthentication for more information. You must be signed into Civis to view that documentation. You can revoke the service token to revoke access to the service.
docker pull civisanalytics/civis-services-flask-demo