0

I'm building a rest API using Flask and SQLAlchemy.

I've encountered one problem: if I delete a resource using a HTTP DELETE that internally calls a SQLAlchemy delete, if I recreate that one element from the database and I try to access the resource using GET I will receive 404 Not Found.

The log indicates: 2021-10-24 11:37:21,736 INFO sqlalchemy.engine.Engine [cached since [..]s ago] {'isbn_1': '12312', 'param_1': 1}.

It looks that the method that does the fetch from the database is for some reason stuck on the state in which the resource does not exist, even if I recreated it with the same details after the HTTP Delete.

This is surely related to the cache, and I'm not sure how to handle this situation.

Model - sqlalchemy

from books import Book
from db import Session, engine

local_session = Session(bind=engine)


def get_book_by_isbn(isbn):
    """
    Wrapper for an ORM call that is retrieving a book by its ISBN.

    :param isbn: isbn code of the book that is to be retrieved
    """
    response = OperationResponseWrapper()
    try:
        response.payload = local_session.query(Book).filter(Book.isbn == isbn).first()
        if not response.payload:
            response.completed_operation = False
        else:
            response.completed_operation = True
    except Exception as e:
        response.erorr = e
        response.completed_operation = False

    return response


def delete_book_by_isbn(isbn):
    """
    Wrapper for an ORM call that is deleting a book by its ISBN.

    :param isbn: isbn code of the book that is to be deleted
    """
    response = OperationResponseWrapper()

    try:
        book_to_delete = local_session.query(Book).filter(Book.isbn == isbn).first()

        if book_to_delete:
            local_session.delete(book_to_delete)
            local_session.commit()
        else:
            response.completed_operation = False

    except Exception as e:
        response.completed_operation = False
        response.erorr = e

    return response

Controller - Flask


from model import get_book_by_isbn, delete_book_by_isbn

[..]
@app.route('/api/bookcollection/books/<isbn>', methods=['GET'])
def get_book(isbn):
    """
    Method that handles a GET request for a book by the ISBN code.

    :param isbn: isbn code of the book that is to be retrieved
    """
    db_response = get_book_by_isbn(str(isbn))
    body = ''
    status = 200
    if db_response.erorr:
        status = 404
        body = ErrorDto(404, str(db_response.erorr), 'EXCEPTION')
    elif not db_response.completed_operation:
        status = 404
        body = ErrorDto(404, 'Requested book does not exist.', 'INVALID_OPERATION')
    else:
        status = 200
        links = LinkDto(request.path, 'books', request.method)
        body = BookDto(db_response.payload, links)

    return jsonify(body.__dict__), status


@app.route('/api/bookcollection/books/<isbn>', methods=['DELETE'])
def delete_book(isbn):
    """
    Method that handles a DELETE request for a book by the ISBN code.

    :param isbn: isbn code of the book that is to be deleted
    """
    db_response = delete_book_by_isbn(isbn)
    body = ''
    status = 200
    if db_response.erorr:
        status = 404
        body = ErrorDto(404, str(db_response.erorr), 'EXCEPTION')
    elif not db_response.completed_operation:
        status = 404
        body = ErrorDto(404, 'Requested book does not exist.', 'INVALID_OPERATION')
    else:
        status = 200
        links = LinkDto(request.path, 'books', request.method)
        body = StatusDto(200, 'Operation was completed successfully.', links)

    return jsonify(body.__dict__), status
davidism
  • 121,510
  • 29
  • 395
  • 339

1 Answers1

0

Ok, seems that I found some solution in this thread: How to disable SQLAlchemy caching?

engine = create_engine(connection_string, echo=True, isolation_level="READ UNCOMMITTED")

adding isolation_level="READ UNCOMMITTED" seems to have helped, but I'm not sure what other implications this action has.