Quickstart

Install Flask-OpenHeart

pip install flask-openheart

Enable OpenHeart Support

After initializing your Flask app, create an OpenHeart instance and call OpenHeart.init_app().

from flask import Flask
from flask_openheart import OpenHeart

app = Flask(__name__)
openheart = OpenHeart()
openheart.init_app(app)

Add the openheart=True argument to any Flask endpoint.

@app.route("/foo/", openheart=True)
def foo(self):
    return "bar"

The “/foo/” endpoint will be created as normal, but an additional “/openheart/foo/” endpoint will be created as well. The OpenHeart endpoint handles all OpenHeart API requests related to “/foo/”.

View/Submit Reactions

Launch the Flask application:

FLASK_APP=app:app flask run

To submit a reaction for “/foo/”, you can make a POST request with curl to the corresponding OpenHeart API endpoint:

curl -d '❤️' -X POST 'http://localhost:5000/openheart/foo/'

To view all the current reactions for “/foo/”, you can make a GET request:

curl 'http://localhost:5000/openheart/foo/'

Insert Reactions in Pages

Whenever a request is handled, if it is for an OpenHeart-enabled endpoint, Flask-OpenHeart will inject information into flask.request pertaining to this endpoint’s reactions.

When generating HTML, you can use this to add information about reactions into your endpoint:

@app.route("/foo/", openheart=True)
def foo(self):
    hearts_count = flask.request.openheart.reactions["❤️"]
    return "<p>Number of ❤️ reactions: {hearts_count}</p>"

Or, if you use templates:

{% set hearts_count = request.openheart.reactions["❤️"] %}
<p>Number of ❤️ reactions: {{ hearts_count }}</p>

You can even render each reaction as a button and wrap the whole thing in an HTML form. This allows visitors to add a reaction by clicking the button.

<form action="{{ request.openheart.post_url }}" method="POST" enctype="text/plain">
{% for reaction, count in request.openheart.reactions.items() %}
  <button name="{{ reaction }}">{{ reaction }} ({{ count }})</button>
{% endfor %}
</form>

Endpoints with Arguments

By default, Flask-OpenHeart stores all reactions for a given endpoint together with each other. However, a single endpoint function might actually represent many distinct pages, in which case it may not be desireable for all of the reactions to get grouped together.

For instance, it is common for a flask endpoint to be structured like:

@app.route("/articles/<id>/")
def foo(id):
    article = get_article_from_database(id)
    if not article:
        abort(404)
    return render_template("article.html", article)

If OpenHeart were enabled for this endpoint, reactions submitted to any article will show up for all articles.

To avoid this, we can provide a slug function. The slug function takes all the same arguments as the endpoint function and returns a unique ID. Flask-OpenHeart will append the slug to the endpoint name whenever it stores and fetches reactions.

The slug function can also return None to indicate that nothing exists with the provided arguments. This causes Flask-OpenHeart to reject all API calls with those arguments.

@app.route("/articles/<id>/", openheart=True)
def foo(id):
    article = get_article_from_database(id)
    if not article:
        abort(404)
    return render_template("article.html", article)

@foo.slug
def foo_slug(id):
    if not article_exists_in_database(id):
        return None
    return id