Introduction

A quote generator is a common web application that people create with a variety of tools. You’ll find the most tutorials on how to do it using JavaScript or Python, but I wanted to see how it’d work using the Wolfram Language, so I reimplemented it and am hosting it in the Cloud.
First, I actually originally did this using the Flask framework (hence why the file structure of “templates” and “static” are there). Then, I re-did it using the Wolfram Web Engine for Python...finally, I figured out how to get it up on the Wolfram Cloud, and that’s what I’ll talk about here.

Create the HTML template and import the CSS

Import the HTML with the template slot. Eventually this will be filled with the dynamically generated quote:
In[]:=
oldhtml=Import["~/templates/quotes.html","String"];
Let’s see what it looks like:
In[]:=
oldhtml
Out[]=
<!DOCTYPE html><html> <head> <link rel="stylesheet" type="text/css" href="/static/styles.css"> </head> <body> <div class="quote_div"> <wolfram:slot id='quote' /> </div>​ <button type="submit" onClick="refreshPage()"> New Quote! </button> </body> <script> function refreshPage() { window.location.reload(); } </script></html>
Create the template with XMLTemplate:
In[]:=
template=XMLTemplate[oldhtml];
Import whatever CSS styling you want:
In[]:=
css=Import["~/static/styles.css","String"];
Mine looks like this:
In[]:=
css
Out[]=
body { background-color: black; background-image: url("background.jpg"); background-size: cover;}​.quote_div { text-align: center; color: white; font-size: 30px; padding: 25px 5px; margin: 15% auto auto;}button { position: fixed; top: 50vh; right: 50vw; border-radius: 4px; background-color: #dd1100; color: white; font-size: 1.1rem; padding: .6rem; text-align: center;}button:hover { border: 2px solid #dd1100; color: #dd1100; background-color: white;}

Get some initial data

The quotes I’m using for the quote generator are from Stephen Wolfram’s WikiQuote page:
In[]:=
page=Import["https://en.wikiquote.org/wiki/Stephen_Wolfram","Data"];
Some quick cleaning of the quotes:
In[]:=
quotes=page[[1,1,8;;12]];
This data is actually exported to an external JSON file, to make it easier to add any new quotes, but for the purposes of showing what the JSON structure looks like, I used ExportString:
In[]:=
data=ExportString[<|​​"quotes"Table[​​"quote"<>ToString[n]quotes[[n]],​​{n,1,Length[quotes]}​​]​​|>,​​"JSON"]
Out[]=
{ "quotes":{ "quote1":"I had a very selfish reason for building Mathematica. I wanted to use it myself, a bit like Galileo got to use his telescope four hundred years ago. But I wanted to look, not at the astronomical universe, but at the computational universe.", "quote2":"It's always seemed like a big mystery how nature, seemingly so effortlessly, manages to produce so much that seems to us so complex. Well, I think we found its secret. It's just sampling what's out there in the computational universe.", "quote3":"Could it be that some place out there in the computational universe, we might find our physical universe?", "quote4":"I'm committed to seeing this project done. To see if within this decade we can finally hold in our hands the rule for our universe, and know where our universe lies in the space of all possible universes.", "quote5":"I think Computation is destined to be the defining idea of our future." }}

Analyze the data and apply it to template

Here we import the data back in using the RawJSON format:
In[]:=
importedData=ImportString[data,"RawJSON"]
Out[]=
quotesquote1I had a very selfish reason for building Mathematica. I wanted to use it myself, a bit like Galileo got to use his telescope four hundred years ago. But I wanted to look, not at the astronomical universe, but at the computational universe.,quote2It's always seemed like a big mystery how nature, seemingly so effortlessly, manages to produce so much that seems to us so complex. Well, I think we found its secret. It's just sampling what's out there in the computational universe.,quote3Could it be that some place out there in the computational universe, we might find our physical universe?,quote4I'm committed to seeing this project done. To see if within this decade we can finally hold in our hands the rule for our universe, and know where our universe lies in the space of all possible universes.,quote5I think Computation is destined to be the defining idea of our future.
We can easily extract the Values, putting them in a list and then selecting a random element from the list with RandomChoice:
In[]:=
q=Values@@importedData;​​selectedQuote:=RandomChoice[q]
Apply the template replacing the placeholder ID with the selected quote:
In[]:=
renderTemplate=TemplateApply[template,<|"quote"selectedQuote|>]
Out[]=
<!DOCTYPE html><html> <head> <link rel="stylesheet" type="text/css" href="/static/styles.css"> </head> <body> <div class="quote_div"> I had a very selfish reason for building Mathematica. I wanted to use it myself, a bit like Galileo got to use his telescope four hundred years ago. But I wanted to look, not at the astronomical universe, but at the computational universe. </div>​ <button type="submit" onClick="refreshPage()"> New Quote! </button> </body> <script> function refreshPage() { window.location.reload(); } </script></html>

Host the web app in the Wolfram Cloud

Like I mentioned previously, I prototyped this for use with the Wolfram Web Engine, which is a Python library for creating web apps written in WL. Some things need to be altered when moving the Wolfram Cloud, since it’s structure is very different and there are Cloud-specific language functions that need to be used.
This section is about putting it all together.

Deploy the CSS:

Specify the MIME type as “text/css” before deploying:

Alter the HTML to take in the deployed stylesheet:

Change the previous stylesheet link in the HTML to point to the new CloudObject:

Deploy the empty HTML template:

The quote generator is empty until we populate it using the template:

Deploy the JSON file:

Create the script:

Here is where things get tricky. You have to alter the blank HTML you just deployed in the Wolfram Cloud, apply the template, then re-deploy to the Cloud:
Run the script to create the quote generator that uses our initial list of quotes:
Once this is done, you’ll need to re-run this script if you add an entry into the JSON file. There’s a way handle that though...

Create the data API:

Create an API that appends a new quote, then re-deploys that new JSON file to the same CloudObject as before:
Create a function that executes the API and which runs the script:

Add a new quote:

Now you can add a new quote just by using this function:
Ta-da!!

Conclusions and future direction

I am pretty satisfied with finally getting a fully functional web app working in the Wolfram Cloud. I was pretty stoked to find a good application to motivate myself to learn more about using templates. I began by writing this same app in Python using the Flask framework, then using the Wolfram Web Engine to prototype the WL version, then making necessary changes to host it in the Wolfram Cloud.
I originally wanted to do this asynchronously: somehow listen to the API I created, and when a new quote is sent to the API to append, I wanted that to trigger the execution of the script automatically. This would let me remove the script altogether from the function and leave it to the Wolfram Cloud to handle. However, I couldn’t get the script to be hosted in the cloud correctly (as a .wl file), and that thwarted my efforts.
You can find the source files (for the prototyped version) in this GitHub repo. I haven’t updated it yet to contain the Cloud-specific changes. I’ll probably do that in the next few days when I have some time. In any case, thanks for reading!