Retrieving JSON with Flask

Flask and JSON

Getting JSON from a REST API and using it in a Flask app

One of the great things about learning new coding techniques is finding new ways to apply them. Taking some inspiration from the best "About" screen - PCalc - and add something fun to the about screen for the asset tracking web app that I am working on. What could be more fun than combining requests, json and dad jokes? Thanks to the LOL Cat Factory tutorial at Talk Python Training's Python Jumpstart by Building 10 Apps, I decided to extend the concepts of downloading data from a REST API and using the data in a project.

My idea was to get some json data containing a dad joke from icanhazdadjoke which offers a free API that returns a dad joke with each GET request. The goal was to create an easter egg in the about screen by adding a link in the footer that only appears on the about screen. To build this, I used the Flask web framework, Jinja2 templates, a Bootstrap modal, and the python requests library.

Flask Routes

The route to pass the data to the template is pretty straight forward, just calling the helper method to get the json data and then passing that data to the template to display for the user.

home_views.py

from flask import render_template

from services import home_services

home = Blueprint('home', __name__, template_folder='templates')

# about page view
@home.route('/about')
def about():
    # get dad joke
    joke = home_services.get_dad_joke()
    return render_template('home/about.html', title='About', joke=joke)

The new concept that I am implementing is retrieving the joke by downloading json. The get_dad_joke() method passes a URL and header parameters (based on icanhzdadjoke API documentation) to a GET request using the requests library, the response to which is stored in variable r. From there, the response is deserialized to text using the loads() method, which returns a python object containing json formatted like:

{
  "id":"wHlOu4o41g",
  "joke":"If you think swimming with dolphins is expensive, you should try swimming with sharks--it cost me an arm and a leg!",
  "status":200
}

With the data in a python object, the function can return only the joke as joke['joke'] back to the view function.

home_service.py

import json
import requests

def get_dad_joke():
    url = "https://icanhazdadjoke.com/"
    headers = {'User-Agent': 'My Library (https://github.com/clark_griswold)', 'Accept': 'application/json'}
    r = requests.get(url, headers=headers)
    joke = json.loads(r.text)
    return joke['joke']

Jinja2 Template

The Jinja2 templates for implementing this are a little challenging because I wanted the dad joke easter egg to only show up on footer of the about page. The code for the footer is not in the about page template, though, it is in the shared _layout.html file that contains the header, navigation, and footer that shows up on all pages. To get the link to the easter egg to only show up on the about page, I added a {% block extra_footer %} to the footer in the _layout.html file. This way, the link and the modal code can stay in the about page and not clutter up the shared layout template file. The other modal in the footer is used to show all of the tools and libraries I use to make the website and should show up in the footer of all of the pages, which is why it is here.

_layout.html

...

<footer id="contentinfo" class="footer mt-auto py-3">
    <div class="container">
        <div class="row">
            <div class="col">
                <span class="">&copy; 2019-2020 COvrebo v2020.0</span>
                {% block extra_footer %}{% endblock %}
            </div>
            <div class="col text-right">
                <!-- Button trigger modal -->
                <a href="#" data-toggle="modal" data-target="#lookUnderTheHood">
                    <span class="footer-modal">Look under the hood</span>
                </a>
            </div>
        </div>
    </div>
</footer>

...

The about page template contains the link and modal code in the {% block extra_footer %} section of the template. The modal code is adapted closely from the example code on the Bootstrap Modal Documentation. The code opens a modal with the data joke, displayed from the {{ joke }} variable.

I have also added a number of code blocks to different parts of the _layout.html template to add page specific css, js, or fonts and I used the {% additional_fonts%} block to add a fun font to display the joke. I only need it here on the about page so this a is great way to keep the layout of the page as simple as possible.

about.html

{% extends "shared/_layout.html" %}

...

{% block extra_footer %}
    <!-- Button trigger modal -->
    <a href="#" data-toggle="modal" data-target="#dadJoke">
        <span class="footer-modal">CanHazFun</span>
    </a>

    <!-- Dad Joke Modal -->
    <div class="modal fade" id="dadJoke" tabindex="-1" aria-labelledby="dadJoke" aria-hidden="true">
        <div class="modal-dialog about-modal-text">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="dadJoke">A Dad Joke:</h5>
                    <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                        <span aria-hidden="true">&times;</span>
                    </button>
                </div>
                <div class="modal-body">
                    <p>
                        <span class="joke-text">{{ joke }}</span>
                    </p>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                </div>
                <div class="about-modal-credit">
                    <span class="text-muted">Thanks <a href="https://icanhazdadjoke.com">icanhazdadjoke.com</a>.</span>
                </div>
            </div>
        </div>
    </div>
{% endblock %}

...

{% block additional_fonts %}
    <link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Permanent+Marker&display=swap" rel="stylesheet">
{% endblock %}

As a longtime  and Mac fan, I have always appreciated the whimsy and easter eggs that the OS occasionally exhibits and the independent developer on the platform have embraced. When I learned how to get data from the web using requests, I just knew there must be a dad joke api out there that I could use to put an easter egg in my web application and it was very easy and rewarding to implement it. My next fun project is to use this code to write a Pelican Plugin for this blog to add the modal to my about page. Perhaps another blog post will be in order when I figure it out...

Resources

Talk Python Training - specifically the LOL Cat Factory App in the Python Jumpstart by Building 10 Apps Course
Real Python - specifically the "Working With JSON Data in Python" guide
icanhzdadjoke
Bootstrap
Requests Library
json Library