(Post originally written in August 2017. Finally got around publishing it...)
I can't sleep in planes. Believe me I've tried. I've been on 12+ hour trips, I've been exhausted, I've twisted and turned, I've used pillows and blankets, but no matter what I do. I can't sleep in planes...or at least in plane seats. The closest I got was on a particular trip where, out of desperation, I pulled down the trays of my neighboring friends, and kinda slept on a makeshift bed atop them. Ultimately, I was told to get down cause I was gonna break the trays, but at least I got in a good hour and a half of sleep.
Anyways, here I am. Stuck on a plane. It's way past midnight and I'm still barely 1/4 of the way through to the mysterious land of Iceland. (Which my younger self, along --I assume-- most other kids, thought was made out of actual ice and was terribly disappointed when I realized it was not. Seems like false advertisment to me.) And this is only the first leg of the trip, but anyways, I digress. As I sit here in this metal can floating through the sky, I decide that I got nothing better to do than to write a post, which has been long overdue. I wonder what to write about, but honestly I am so burnt out and tired that the only possible thing I know I can share in this low functioning state of mind is...*drumroll*: "building a small webapp using flask, javascript and AJAX calls". Yes, it turns out I love Flask, and building small webapps like this is something I can do without having to really think.
So if you can deal with my ramblings and are curious to know how to build a simple webapp using a flask webserver as a backend and a javascript-enabled front end, and have them both communicate through AJAX calls then follow me (or just keep reading)!
In the true spirit of rambling, I have a bit of a secret love with web development. It is something I find entertaining, specially if I'm working alongside a good UI/UX designer (cause man... CSS is a bit of a drag). Javascript and Python are just super fun to work with and its impressive what you can build with just a few minutes of coding. So considering that now web has seeped in everywhere, it is a good idea to have at least a basic understanding of how to prototype different webapps without suffering too much.
* Follow me @konukoii for more interesting content!
A Simple WebApp Structure
A WebApp is essentially an application that lives as a website. That might be a bit to broad, but essentially it is a website that has a purpose (other than to display a static piece of information). It is dynamic and it usually requires some sort of connection to a database or other sources of information.
Our webapp will have two main pieces (as is the case with most wepabpps out there):
- The Front-End: This is the part of the code/markup that is running on the user's computer.
- Visuals: The actual visuals / UI setup that gets designed in HTML markup, CSS, and other nifty things I generally don't like messing around with.
- Execution: The actual code that runs on the client (usually javascript). It is in charge of communicating with the backend and updating the front-end.
- The Back-End: this is the part of the code that runs on the server. It usually does some sort of database lookup, heavy calculations, or communicates with other services. In other words, it's a piece of code that for whatever reason must recide on the server (otherwise you would just be running it out of the client and saving precious computation time on your server).
Ok, let's keep moving folks...
Our Project
For this project we will build a small leaderboard. Our webapp will allow us to:
- View the leaderboard
- Add a new leaderboard entry
- Delete a leaderboard entry
Remember the main point of this is to learn how to use Flask + Javascript + w/ AJAX calls. Also, to pass the time as this trip drags on forever.....hey at least the sun is coming up now 🙂
At this point you can start with either the front-end or the back-end. I've actually never read any information on which one you should start first, but I kinda like starting with the back-end; It just seems like a good idea to first determine what can and can't be done by your web-app, and then adding a front-end to it.
Backend: Introducing Flask
To build our back end, we will use Python's library Flask. Flask is an awesome Python web micro-framework. As I understand it, a micro-framework is essentially a barebones webserver, where you get to install the plug-ins and actual tools you need. The benefit of using Flask is that it is brutally simple. Unliike Django and other frameworks that have a higher learning curve, 4 lines of code will be enought to get a flask server up and running.
Let's get started.
from flask import * import jsonpickle app = Flask(__name__) ######################## # Flask Server Example # ######################## ##LEADERBOARD ## This will be a list with simple dict inside (eg. [{name: Joe, score: 10},{name: Jane, score: 20}]) leaderboard = [] id = 0 # INDEX PAGE @app.route('/') def home(): return render_template('index.html') # GET LEADERBOARD @app.route('/api/getleaders') def get_leader(): global leaderboard print "Getting Leaderboard" print leaderboard return jsonpickle.encode(leaderboard) # ADD ENTRY @app.route('/api/addentry',methods=['POST']) def add_entry(): global leaderboard,id print "Adding Entry" content = request.get_json(silent=False) id += 1; leaderboard += [{"id":id,"name":content["name"],"score":content["score"]}] return jsonpickle.encode(leaderboard) # REMOVE ENTRY @app.route('/api/rmentry/', methods=['DELETE']) def rm_entry(entry_id): global leaderboard print "Removing Entry!" for entry in leaderboard: if entry["id"] == entry_id: leaderboard.remove(entry) break; return jsonpickle.encode(leaderboard) if __name__ == "__main__": app.debug = True app.run(port=80)
Now those are the API calls that our front-end will make use off to dynamically update our website. Notice I used POST and GET calls since these are the two most common calls you'll encounter, however you can use a bunch of others (and if you are really nifty you could make some custom calls for the heck of it). Let's move on to the front-end:
Frontend
On the frontend we can use javascript to request and recieve information from the user. This is done through AJAX calls. Notice these calls are asycnhronus, so what this means is that you have to be conscientious that when you do a call, it will not return instantly, instead you must use callback functions. You also have to be aware, and consider edge cases such as server-timeouts that can leave the front-end displaying differing information from the back-end. In our particular experiment, this wouldn't be too big of a deal, but with more complex applications you always want to think through different error-prone situations.
This code will go into an index.html located at inside the template folder. If you noticed at the start of the python flask server file, there is a segment that stipulates that when a browser requests the base url "/" (e.g. localhost), they shall be rendered the "index.html" file. This is technically optional as you could host this file via Apache or Nginx, while maintaining the python back-end hosted separately.
The following snippet contains all the static code in the website, as you can imagine this is the things displayed on the website that don't really change. We can leave sections (e.g. divs, spans, etc.) with specific ids to use later on to dynamically inject data in there. In a way you can simply think of this as a template.
<h1>Leaderboard</h1> <div id="leaderboard"></div> <hr> Name: <input id="name" type="text" placeholder="John Doe" /> Score: <input id="score" type="text" placeholder="150" /> <button>Add</button> <hr>
The following snippet contains the javascript code that will take care of making the AJAX calls to retrieve/push data onto our back-end. It will also take care of modifying the website. Bare in mind, I'm not gonna be doing crazy modifications and there are other tools and libraries that you can use to do more slick looking modifications.
<!-- Im importing jquery from their website, but you can manually download it and add it to your site --> <script src="//code.jquery.com/jquery-1.11.3.min.js"></script> <script type="text/javascript"> //UPDATE LEADERBOARD // This function takes in the data retrieved from the back-end and dynamically updates the leaderboard. function UPDATE_LEADERBOARD(lb_data){ // This is a hacky form of checking that everything // you are given is always an object and not a string // You can set response headers in flask to mimetype json // so you don't have to do this. But I was kinda lazy. if (typeof(lb_data) == "string"){ lb_data = JSON.parse(lb_data); } console.log(lb_data) lb_html = "<table>"; lb_html += "<tr><th>Name</th><th>Score</th></tr>"; if (lb_data != []){ for(i = 0; i < lb_data.length; i++){ lb_html += "<tr><th>"+lb_data[i].name+"</th><th>"+lb_data[i].score+"</th><th><button OnClick='RM_ENTRY("+lb_data[i].id+")'>X</button></th></tr>"; } } lb_html += "</table>"; $('#leaderboard').html(lb_html); } //GET LEADERBOARD function GET_LEADERBOARD(){ var urlstring = "../api/getleaders"; $.ajax({ url: urlstring, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, type: 'get', success: function (data) { console.log("Get Leaderboard: Successful!"); UPDATE_LEADERBOARD(data); }, error: function(data){ console.log("Get Leaderboard: Error!"); //alert("Coudn't Get Leaderboard!"); } }); } //ADD ENTRY function ADD_ENTRY(){ var urlstring = "../api/addentry"; var new_entry = { name: $("#name").val(), score: $("#score").val(), } $.ajax({ url: urlstring, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, type: 'post', dataType: 'json', success: function (data) { console.log("Add Entry: Successful!"); UPDATE_LEADERBOARD(data); }, error: function(data){ console.log("Add Entry: Error!"); alert("Coudn't Add Entry!"); }, data: JSON.stringify(new_entry) }); } //REMOVE ENTRY function RM_ENTRY(id){ var urlstring = "../api/rmentry/"+id; $.ajax({ url: urlstring, headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' }, type: 'delete', success: function (data) { console.log("Remove Entry: Successful!"); UPDATE_LEADERBOARD(data); }, error: function(data){ console.log("Remove Entry: Error!"); alert("Coudn't Remove Entry!"); } }); } //Run When Document is Loaded window.onload = function(){ GET_LEADERBOARD(); //Get the leaderboard upon loading the page setInterval(GET_LEADERBOARD, 5000); //Every so often check leaderboard to see if it changed. Try using different tabs :) }; </script>
When we put everything together, we will see a rather bare-bones, yet functional page.
Conclusion
Well, I hope this brief write-up has showcased the simplicity and power of Flask, and potentially inspired you to take a look at such great tool! If you've always been intrigued in building web-apps, but never gotten around to actually doing it, I wholeheartedly recommend using Flask for fun and quick prototyping. As always, if you have any comments, suggestions, or questions feel free to hit me up!
I put (copy and paste) everything togheter (the backend in a .py file and the frontend in a .html file) but i doesn't work. Help me please is very important. I look forward to hear from you. thank you
What error are you encountering?
Some things to check for when copy/pasting the code:
- Have you installed the proper dependencies?
- Is there some indentation issue (or perhaps some special character that got copied along)?