Search code examples
pythonflaskazure-web-app-serviceazure-postgresql

Flask API works correctly locally but returns 415 on Azure App Service


Current environment

  • Python 3.10
  • Flask 2.3.2 and waitress 2.1.2
  • Postgresql DB on Azure Postgresql managed service (flexible server)
  • App Service running docker container for the server with same requirements as above
  • Calling endpoints from python using requests

Code and use case

Relevant code for the server:

from flask import Flask, jsonify, request
from waitress import serve
from paste.translogger import TransLogger

# --- Routes definition --- #
@app.route(f"{API_ENDPOINT_PREFIX}/hello", methods=["GET"])
def hello():
    logging.info("Hello")
    return jsonify({"message": "Hello!"})


@app.route(f"{API_ENDPOINT_PREFIX}/filter/<tablename>", methods=["GET"])
def get_filter_options(tablename: str):
    request_data = request.get_json()
    logging.debug(f"Request data: {request_data}")

    # Doing stuff here and obtaining a variable options

    logging.info(f"Retrieved {len(options)} filter options for table '{tablename}'")
    return jsonify({"filters": options})


# --- Main --- #
if __name__ == "__main__":
    logging.info(f"Welcome to Flask server")
    serve(
        TransLogger(app, setup_console_handler=False),
        host=API_ENDPOINT_HOST,
        port=API_ENDPOINT_PORT,
    )

API_ENDPOINT_PREFIX is set to /api.

Note that /api/hello is an endpoint for testing purposes, while /api/filter/<tablename> is supposed to be a working api to retrieve possible options for filter fields and return them to an ui. This api connects to the postgresql database hosted on Azure.

I launched this locally on localhost:8000 and all works as expected. I also deployed the same to Azure App Service, and what happens is the the /api/hello endpoint still works fine, while the /api/filter/<tablename> returns 415.

In both cases the api is called using the following snippet of code:

header = {"Content-Type": "application/json", "Accept": "application/json"}

requests.get(
        f"{BASE_API_URL}/filter/tablename",
        data=json.dumps({"filters": {}}),
        headers=header,
    )

where BASE_API_URL is alternatively http://localhost:8000/api when running locally or http://app-service-name.azurewebsites.net/api when running on app service.

What I've checked

General suggestions say to include the Content-Type and Accept header, which I do in any case. I also checked the connection between app service and hosted db, supposing that some problem may arise if the two services cannot communicate. TO this end, I created a Service Connector on the app service whose target is the hosted db, so I suppose everything is ok.

What seems strange to me is that the /api/hello endpoint, which does not require any payload, works fine in both environments, while the api/filter/<tablename> endpoint, which requires a payload, works differently.

Am I missing something? Which other actions can I take to further investigate this?


Solution

  • I found that the problem was simply that Azure App Service exposes the APIs through https instead of http. Just putting https in each URL solved the issue.