Build a Simple LMS-Integrated Quiz App Using Python, React.js, and LTI 1.3

Update: 11/20/2023: Please use the newer PART 1 of this series here:
Build a Simple LMS-Integrated Quiz App Using Python, React.js, and LTI 1.3 – Part 1
The code below references an older Python code that’s not a part of pyLTI1p3.

Update: 5/3/2023: In the process of creating part 2 of this series, I discovered a lot in my research (like, maybe this isn’t the right path for a simple solution) and will be expanding by finding a more viable and maintainable option. Several folks have reached out to me about this article, only to discover that they could use a simpler approach. I began asking questions like: 1) Why use React.js when I could use Flask’s templating engine? Perhaps because React is more common than something like Jinja? 2) Why not use a framework that is built for this purpose, such as LTIjs? More to share on this topic at a future date as I continue to explore the latest frameworks like Vue.js 3 and using Django instead of Flask from the outset. I love it that this is already developing into a tiny community, helping to give this site some direction… and if you feel strongly about the direction I’m taking with this post / series, please click “leave a comment” in the title sidebar.


The project idea is all in the title… Let’s plan out what is involved and what the result might look like.

This is just a high-level overview of a Quiz application built with Python Flask and React.js Javascript library. We’ll have multiple choice as our only option — again just keeping the development effort somewhat simple. The actual implementation will depend on the requirements below and the LMS that we are integrating with BUT I want to make this as agnostic as possible, where the LMS really shouldn’t matter as long as the platform we’re integrating with is LTI1.3/Advantage certified.

Dall-E generated: a surrealist painting of a cyberpunk, sitting at a desk in a desert at night

1. Flask Backend

  • Create a Flask application that implements LTI 1.3 by using an LTI library. I think we have a good idea of what that will be: PyLTI1p3.
  • Create a RESTful API for the quiz application that allows React frontend to retrieve questions and submit answers.
  • The backend should also be able to store the scores of the students and their grading status. Perhaps we’ll just use SQLite, although I believe this isn’t the best choice. The intention here will be to migrate to PostgreSQL but SQLite is good enough for establishing the initial database schema.

2. React Front-end

  • Create a React application that fetches questions from the Flask backend and displays them to the user.
  • Allow users to submit answers to the questions and provide feedback on their responses.
  • The frontend should also be able to retrieve the scores and grading status of the students.
  • If this were Django, and since it’s not a complex build, I would likely skip this part and implement the front-end part of the stack through it’s native templating engine. My favorite options are Vue.js and React.js because of their flexibility and they are fine to use with Django.

3. Integration with the LMS

  • Implement the LTI 1.3 protocol in the Flask backend to communicate with the LMS.
  • Pass the scores of the students back to the LMS and create a gradebook column in the LMS.
  • Post the scores along with grading status to the LMS.

Preview of Step 2 (which I will post soon) — Using PyLTI1p3 with Flask might look something like this. Let’s explore further in Part 2, where we’ll refine this and test it out.

from flask import Flask, request
from pylti1p3.flask import lti

app = Flask(__name__)

@app.route('/api/questions', methods=['GET'])
@lti(request='launch', role='instructor')
def get_questions():
    # Retrieve questions from the database
    # ...

    return json.dumps(questions)

@app.route('/api/scores', methods=['POST'])
@lti(request='launch', role='student')
def submit_score():
    score = request.form['score']
    # Store the score in the database
    # ...

    # Pass the score back to the LMS and create a gradebook column
    request.lti_outcome_service().post_replace_result(score)
    return 'Score submitted successfully'

if __name__ == '__main__':
    app.run()

This code uses the @lti decorator from pylti1p3 to implement the LTI 1.3 protocol and check if the request is valid and if the user has the correct role.

The get_questions function retrieves the questions from the database and returns them to the frontend.

The submit_score function stores the score in the database and passes it back to the LMS using the post_replace_result method from the LTI outcome service.

This is just sample code and we will need to make many modifications in order to fit the specific requirements of our project.

Thank you and have a great day!

3 Comments

  1. Hi Eric,

    Thank you for this article series I am really looking forward to part 2. In your preview code for part 2 you mention there is a @lti decorator for pylti1p3? I cannot find any information in the documention about it and the import doesn’t exist. Could you point me to where this can be found?

    Reply

    1. Greetings, Tyler. Thank you for the comment. The @lti decorator piece is a mixup and is from a library called PyLTI (which supported only earlier LTI versions) that appeared in some older code. Here’s an outdated doc with the same: https://pylti.readthedocs.io/en/latest/flask.html.

      I’m in the process of working on a corrected version of this post using PyLTIp3 this week. Your timing is good on this because I need this solution working for a project. Stay tuned for a revised part 1 — followed by a part 2!

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

86 − = 78

This site uses Akismet to reduce spam. Learn how your comment data is processed.