question

James Battersby avatar image
James Battersby asked

Azure Function: BadRequestObjectResult - return data?

I'm currently executing an Azure function from the legacy cloudscript. The Azure function is correctly capturing an error and returns a BadRequestObjectResult along with a message (I'd prefer it to be be stringified JSON object). Below is the response I receive from the cloudscript invocation:

{
            "Level": "Info",
            "Message": "Exception: {\"code\":400,\"status\":\"BadRequest\",\"error\":\"CloudScriptAzureFunctionsHTTPRequestError\",\"errorCode\":1473,\"errorMessage\":\"Invocation of cloud script function StoreTransaction failed\"}",
            "Data": null
        }

As you can see there is no additional data returned. Is there a way to pass the error data back?

For clarification:

Cloudscript Invocation:

function executeAzureFunction(functionName, functionParameter)
{
let url = `https://${script.titleId}.playfabapi.com/Authentication/GetEntityToken`;let method = "POST";let headers = {
"X-SecretKey": PLAYFAB_SECRET_KEY
};
let contentType = "application/json";
let contentBody = {
Entity: {
Id: script.titleId,Type: "title"}
};
let response = JSON.parse(http.request(url, method, JSON.stringify(contentBody), contentType, headers));
url = `https://${script.titleId}.playfabapi.com/CloudScript/ExecuteFunction`;
headers = {
"X-EntityToken": response.data.EntityToken
};
contentBody = {
FunctionName: functionName,FunctionParameter: functionParameter
};
response = JSON.parse(http.request(url, method, JSON.stringify(contentBody), contentType, headers));
return response;

Azure Function:

[FunctionName("StoreTransaction")]
public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
{ 
//Found something wrong, return a BadRequestObjectResult
return new BadRequestObjectResult("something went wrong");
}
CloudScript
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

JayZuo avatar image
JayZuo answered

There are two problems here:

1. We should never call Cloud Function from Legacy Cloud Script. There would be no point in doing it that way - it would needlessly complicate the flow making debugging difficult, and it would double your execution count and execution time meter costs.

2. We should not return "BadRequestObjectResult" if we want to get the result with ExecuteFunction method. In the backend, ExecuteFunction will check the status code returned by your Azure Function. If the status code is not in the Successful range (200-299), it will return the "CloudScriptAzureFunctionsHTTPRequestError" as you've seen. Thus, to get the "Something went wrong" message, you will also need to return an "OkObjectResult".

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Gosen Gao avatar image
Gosen Gao answered

If you want to do error handling in Azure Function, please ensure that the function will not be interrupted when an error occurs, and return the error message as a result.

You can follow Tutorial: Debugging CloudScript using Azure Functions with the Azure portal to check the log stream in Azure portal to see if this function has been triggered properly. If there is no log in the stream when you try to call this function, then there should be something incorrect when you register this Azure function to PlayFab. Please check the function URL and make sure it can be used to trigger the function.

4 comments
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

James Battersby avatar image James Battersby commented ·

I think there's some confusion here.

The function is definitely called - I can see the log streaming as it works its way through the function. The question is if we catch an issue and try to fail gracefully (for example running within a try/catch block) by returning a BadRequestObjectResult as opposed to a OkObjectResult can we not return data about that particular error, even if it just a string or a custom error code?

Or should we return an OkObjectResult regardless in the hopes of returning any kind of meaningful data, returning any relevant error data as necessary?

0 Likes 0 ·
James Battersby avatar image James Battersby James Battersby commented ·

Same occurs if you directly call the function from Playfab Admin.

A simplistic example:

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace My.Functions
{
  public static class MyFunction
  {
    [System.Serializable]
    struct Response
    {
      public byte code;
      public string message;
    }

    [FunctionName("MyFunction")]
    public static async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
        ILogger log)
    {
      try
      {
        throw new Exception();//comment out for a successful response
        return new OkObjectResult(new Response{
          code = 0,
          message = "All good"
        });
      } 
      catch (Exception e)  
      {
        return new BadRequestObjectResult(new Response{
          code = 255,
          message = "Something went wrong"
        });
      }
    }
  }
}
0 Likes 0 ·
James Battersby avatar image James Battersby James Battersby commented ·

Successful response:

{
    "ExecutionTimeMilliseconds": 1063,
    "FunctionName": "MyFunction",
    "FunctionResult": {
        "code": 0,
        "message": "All good"
    },
    "FunctionResultTooLarge": null,
    "Error": null,
    "Status": 200
}

Error response:

{
    "ExecutionTimeMilliseconds": 0,
    "FunctionName": "MyFunction",
    "FunctionResult": null,
    "FunctionResultTooLarge": null,
    "Error": {
        "Code": 0,
        "Status": "BadRequest",
        "ErrorCode": 1473,
        "ErrorMessage": "Invocation of cloud script function MyFunction failed"
    },
    "Status": 400
}
0 Likes 0 ·
Show more comments

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.