Providing an HTTP Error Response in Azure Functions

Posted by

I recently found myself wanting to standardize the error response from some HTTP-based Azure Functions. Depending on the error, the functions returned a 4xx or 5xx status code, with a response body that was at times a JSON object, other times a basic string. It was all over the place.

That’s where RFC7807, also known as http-problem, or problem details, comes in to play. Its goal is to standardize the body of an error response from an HTTP endpoint. The contract has five fields:

  • Status: The status code of the response.
  • Type: A URI-formed error identifier that uniquely identifies the error.
  • Title: A short description of the error that could help developers understand what’s happened.
  • Detail: A more verbose description of the error, with additional details that could help in debugging.
  • Instance: The specific occurence of the problem.

Functions are meant to be short and sweet, so I wanted the approach to formatting problem details to be just as straightforward. Ultimately, the approach relies on three classes to get it done.

Dealing With Problem Details

The first class that is needed is ProblemDetails. It’s provided in the Microsoft.AspNetCore.Mvc namespace, requiring a dependency on ASP.NET Core. You can create your own class for it within your functions project if you’d rather avoid taking on such a large dependency.

public class ProblemDetails
{
	public string Type { get; set; }
	public string Title { get; set; }
	public int? Status { get; set; }
	public string Detail { get; set; }
	public string Instance { get; set; }
}

The next step is to create a class that inherits from ObjectResult that accepts an instance of the ProblemDetails. ProblemObjectResult is what will be returned by the functions, serializing the ProblemDetails object into the response body.

public class ProblemObjectResult : ObjectResult
{
	public ProblemObjectResult(ProblemDetails value) : base(value)
	{
		StatusCode = (int)value.Status;
	}
}

Finally, the ErrorResponse class has a series of static methods to create common error responses:

public class ErrorResponse
{
	public static ObjectResult CreateResponse(
		HttpStatusCode statusCode,
		string type,
		string title = "",
		string detail = "",
		string instance = "")
	{
		var problem = new ProblemDetails()
		{
			Status = (int)statusCode,
			Type = type,
			Title = title,
			Instance = instance,
			Detail = detail
		};

		return new ProblemObjectResult(problem, statusCode);
	}

	public static ObjectResult BadRequest(
		string type,
		string title = "",
		string detail = "",
		string instance = "")
	{
		return CreateResponse(HttpStatusCode.BadRequest, type, title, detail, instance);
	}

	public static ObjectResult InternalServerError(
		string type = "unexpected-error",
		string title = "",
		string detail = "",
		string instance = "")
	{
		return CreateResponse(HttpStatusCode.InternalServerError, type, title, detail, instance);
	}

	public static ObjectResult NotFound(
		string type,
		string title = "",
		string detail = "",
		string instance = "")
	{
		return CreateResponse(HttpStatusCode.NotFound, type, title, detail, instance);
	}
}

With that last piece in place, it’s now a matter of calling the appropriate method from within the functions. Here are a few sample calls from my functions project:

if (!validFlightId)
{
	return ErrorResponse.BadRequest(type: "/invalid-flightid", instance: $"/flight/{unsanitizedflightId}");
}
...
return ErrorResponse.NotFound(type: "/invalid-flightid", instance: $"/flight/{unsanitizedflightId}");
...
return ErrorResponse.BadRequest(type: "/invalid-request", detail: errorMessages.Aggregate((i, j) => i + ", " + j));

The response that will be returned in the case of a 4xx or 5xx error will resemble the following:

400 BAD REQUEST
{
    "type": "invalid-schema",
    "title": "not-specified",
    "status": 400,
    "detail": "Required properties are missing from object: departing. Path '', line 1, position 1.",
    "instance": "not-specified"
}

Possible Improvements

Right now, every property of the ProblemDetails object is serialized in the response. Ideally, I’d like to serialize only the properties that are set, but functions doesn’t expose a way to modify its JSON serializer settings.

Overall, I’m happy with the above solution. It’s lightweight to implement, and it provides a standard response for any failed HTTP requests. The next step would be to move it out into a reusable package that can be used across function projects.


Did you find the information you were looking for? Is there something missing from this article that would make it more useful to you? Do you have a follow-up question? Feel free to reach out to me on Twitter or LinkedIn. I’d be glad to help out.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s