How to trigger a Azure Function with parameters from a POST request

Question:

I need to send a POST request (with user captured data) to azure function and I would like Azure function to use this as parameters and run.

I can see there are many ways to trigger an Azure function in the docoumentation however I have not been able to figure out how to do the above when supplying user input.

For more context I am developing a simple user form where the user enters some data. Once the user clicks submit I will need fire off a POST request to Azure function to carry out some processing.

Asked By: m o

||

Answers:

Below is a sample code for HTTP POST request triggered Function App.

functions.json:

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

__init__.py:

import logging
import azure.functions as func
import onnxruntime
from PIL import Image
import numpy as np
import io

def main(req: func.HttpRequest, context: func.Context) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    body = req.get_body()

    try:
        image = Image.open(io.BytesIO(body))
    except IOError:
        return func.HttpResponse(
                "Bad input. Unable to cast request body to an image format.",
                status_code=400
        )

    result = run_inference(image, context)

    return func.HttpResponse(result)

def run_inference(image, context):
    # See https://github.com/onnx/models/tree/master/vision/style_transfer/fast_neural_style
    # for implementation details
    model_path = f'{context.function_directory}/rain_princess.onnx'
    session = onnxruntime.InferenceSession(model_path)
    metadata = session.get_modelmeta()
    logging.info(f'Model metadata:n' +
        f'    Graph name: {metadata.graph_name}n' +
        f'    Model version: {metadata.version}n' +
        f'    Producer: {metadata.producer_name}')

    # Preprocess image
    original_image_size = image.size[0], image.size[1]
    logging.info('Preprocessing image...')
    # Model expects a 224x224 shape input
    image = image.resize((224, 224), Image.LANCZOS)
    bands = image.getbands()
    if bands == ('R', 'G', 'B'):
        logging.info(f'Image is RGB. No conversion necessary.')
    else:
        logging.info(f'Image is {bands}, converting to RGB...')
        image = image.convert('RGB')

    x = np.array(image).astype('float32')
    x = np.transpose(x, [2, 0, 1])
    x = np.expand_dims(x, axis=0)

    output_name = session.get_outputs()[0].name
    input_name = session.get_inputs()[0].name
    logging.info('Running inference on ONNX model...')
    result = session.run([output_name], {input_name: x})[0][0]

    # Postprocess image
    result = np.clip(result, 0, 255)
    result = result.transpose(1,2,0).astype("uint8")
    img = Image.fromarray(result)
    max_width  = 800
    height = int(max_width * original_image_size[1] / original_image_size[0])
    # Upsample and correct aspect ratio for final image
    img = img.resize((max_width, height), Image.BICUBIC)
    
    # Store inferred image as in memory byte array
    img_byte_arr = io.BytesIO()
    # Convert composite to RGB so we can return JPEG
    img.convert('RGB').save(img_byte_arr, format='JPEG')
    final_image = img_byte_arr.getvalue()

    return final_image

Check out this GitHub sample of Python POST request: https://github.com/yokawasa/azure-functions-python-samples/tree/master/v2functions/http-trigger-onnx-model

Answered By: Harshita Singh

The data from the submitted form will be a Bytes object. You must convert it to a string and then parse the parameters. This sample code handles the submission of a basic contact info form.

import logging

import azure.functions as func

from urllib.parse import parse_qs


def main(req: func.HttpRequest) -> func.HttpResponse:
    # This function will parse the response of a form submitted using the POST method
    # The request body is a Bytes object
    # You must first decode the Bytes object to a string
    # Then you can parse the string using urllib parse_qs

    logging.info("Python HTTP trigger function processed a request.")
    req_body_bytes = req.get_body()
    logging.info(f"Request Bytes: {req_body_bytes}")
    req_body = req_body_bytes.decode("utf-8")
    logging.info(f"Request: {req_body}")

    first_name = parse_qs(req_body)["first_name"][0]
    last_name = parse_qs(req_body)["last_name"][0]
    email = parse_qs(req_body)["email"][0]
    cell_phone = parse_qs(req_body)["cell_phone"][0]

    return func.HttpResponse(
        f"You submitted this information: {first_name} {last_name} {email} 
        {cell_phone}",
        status_code=200,
    )
Answered By: STEM FabLab

This snippet can work: https://github.com/yuenci/Azure-Functions-Request-CORS

# post
import logging

import azure.functions as func
import json


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    req_body_bytes = req.get_body()
    req_body = req_body_bytes.decode("utf-8")

    logging.info(f"Request: {req_body}")

    content = json.loads(req_body)

    first_name = content["first_name"]
    last_name = content["last_name"]

    return func.HttpResponse(
        f"Hello, {first_name} {last_name}. This HTTP triggered function executed successfully.",
        status_code=200
    )

Make sure post method is allowed

// function.json

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post" // notice
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}
Answered By: Innis