1
votes

I have written an Azure Function that persists data to a Cosmos collection:

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    try {
        if (req.body) {
            const body: Body = req.body

            context.bindings.cosmosDocument = JSON.stringify(body);
            context.res = {
                status: 200,
                body: 'Successfully persisted document'
            };
        }
    } catch (error) {
        context.res = {
            status: 400,
            body: 'Colliding id'
        }
    }
}

I am handling errors according to the documentation.

My payload looks like this:

{
    "shipmentId": "shipmentId",
    "timestamp": 1586327829354,
    "totalVolume": 1,
    "totalWeight": 1,
    "packages": [{
        "packageId": "courierPackageId",
        "shipmentId": "shipmentId",
        "weight:": 1000,
        "dimensions": {
            "length": 100,
            "width": 100,
            "height": 100
        }
    }]
}

However, when I try to persist something that will have a colliding id in the database, that error is not caught.

I see the following error:

Entity with the specified id already exists in the system

And when I call this trigger through Postman, I get status 500 and no message body.

In this issue on Github, a solution is suggested for C#.

How can I handle this exception and give the API user a meaningful message? What is the usual approach when building APIs in Azure Function and handling errors produced by output bindings?

1
Can you show the body you post? - Bowman Zhu
@BowmanZhu see my updated post. The works, and it rejects duplicates as it should, I just want to be able to act on it. - jokarl
Works fine on my side, I am trying to check it out. - Bowman Zhu
The request body will be saved to a random id, if you want to update, you should specify the id in the request body. - Bowman Zhu
I want to have the generated id, my issue is that I cannot notify an end user if a collision occurs. If a error happens downstream in cosmos output, it seems to be out of my control. - jokarl

1 Answers

1
votes

On my side, it works fine. I can upload and also update.

This is the code of my function app:

index.ts:

import { AzureFunction, Context, HttpRequest } from "@azure/functions"

const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> {
    context.log('HTTP trigger function processed a request.');
    const name = (req.query.name || (req.body && req.body.name));

    try {
        if (req.body) {
            const body: Body = req.body

            context.bindings.employeeDocument = JSON.stringify(body);
            context.res = {
                status: 200,
                body: 'Successfully persisted document'
            };
        }
    } catch (error) {
        context.res = {
            status: 400,
            body: 'Colliding id'
        }
    }

    if (name) {
        context.res = {
            // status: 200, /* Defaults to 200 */
            body: "Hello " + (req.query.name || req.body.name)
        };
    }
    else {
        context.res = {
            status: 400,
            body: "Please pass a name on the query string or in the request body"
        };
    }
};

export default httpTrigger;

function.json:

{
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "name": "employeeDocument",
      "type": "cosmosDB",
      "databaseName": "ToDoList",
      "collectionName": "Items",
      "createIfNotExists": true,
      "connectionStringSetting": "MyAccount_COSMOSDB",
      "direction": "out"
    }
  ],
  "scriptFile": "../dist/HttpTrigger1/index.js"
}

And This is the postman:(I have put the json file in the test.txt)

enter image description here

test.txt:

{
    "id": "934a2153-fdb1-40e3-9e90-61c43fcef220",
    "shipmentId": "shipmentId2",
    "timestamp": 1586327829354,
    "totalVolume": 1,
    "totalWeight": 1,
    "packages": [{
        "packageId": "courierPackageId",
        "shipmentId": "shipmentId",
        "weight:": 1000,
        "dimensions": {
            "length": 100,
            "width": 100,
            "height": 100
        }
    }]
}

In the case of the same id, if you change other parts and then trigger the function, azure cosmosdb will be updated accordingly.