Omitting Empty Elements on JSON Payloads

I am working on a Logic Apps project where the client API validates the elements before saving, and is not expecting null values to come through. For example, in the payload below:

{
	"Email": {
		"StartDate": "21/11/2018",
		"EmailAddress": "randel.menezes@nzhomeloans.co.nz",
		"EmailStatus": "Active"
	},
	"AlternateEmail": {
		"StartDate": "21/11/2018",
		"EmailAddress": null,
		"EmailStatus": "Inactive"
	}
}

It doesn’t expect the data like showed above (which is fair enough), but also don’t like “AlternateEmail”: null. Instead it expects the AlternateEmail element to be dropped from the payload. Trying to do this with logic apps components would make the workflow really hard to maintain later (and to be honest I don’t even sure if I would be able to pull that off with out of the box components like composite and variables).

 I probably could have move this part to API Management (since it is also part of the solution), but I would prefer to maintain my mapping in a single location and I had already most of my mapping in Azure Functions. But I was still scratching my head on how I would deal with this without handcrafting JSON inside the Azure Function.

What I realized that this is a serialization problem, right? If only I could have more control of the object serialization – if I could do this with XMLSerializer, I was pretty sure I could do the same with JSONSerializer… And for sure I could. A couple of annotation on my model classes and voilá! Crisis averted… So my model looked like this:

[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class EmailProfile
{
	[JsonProperty(PropertyName = "Email")]
	public Email Email { get; set; }
	[JsonProperty(PropertyName = "AlternativeEmail")]
	public Email AlternativeEmail { get; set; }
}

[JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]
public class Email
{
	[JsonProperty(PropertyName = "StartDate")]
	public string StartDate { get; set; }
	[JsonProperty(PropertyName = "EmailAddress")]
	public string EmailAddress { get; set; }
	[JsonProperty(PropertyName = "EmailStatus")]
	public string EmailStatus { get; set; }
}

The trick here was the [JsonObject(ItemNullValueHandling = NullValueHandling.Ignore)]. Using that attribute, the serializer would ignore the null values, which would give me the result that I was looking for, which was – if I have an element that is null, that element would not be represented in the serialized JSON.

Then it was just a matter or not populate AlternateEmail at all if the email was null, like this:

EmailProfile profile = new EmailProfile();

Email email = GetEmail(data.agency._primaryemail_label, data);
if (!string.IsNullOrEmpty(email.EmailAddress))
	profile.Email = email;

Email alternativeEmail = GetEmail(data.agency.alternateemail_label, data);
if (!string.IsNullOrEmpty(alternativeEmail.EmailAddress))
	profile.AlternativeEmail= alternativeEmail;

If you are really paying attention to the JSON annotation you would probably ask: “Hey, I got the NullValueHandling thingie, but why the JSONProperty annotation?” Well, for some reason the serialization by default was returning my elements in camel case (alternativeEmail for example), so I fixed that forcing the name of each property.

So in the end, my API Management call looked like this:

"Post_Contact": {
"inputs": {
	"api": {
		"id": "/subscriptions/ba41ff3a-************-35216905e89e/resourceGroups/Common_Resources/providers/Microsoft.ApiManagement/service/wsilveiranz/apis/contact"
	},
	"body": {
		"Addresses": "@body('ParseContactAddress')",
		"DateofBirth": "@if(equals(body('Contact')['birthdate'], null), null, formatDateTime(body('Contact')['birthdate'], 'dd/MM/yyyy'))",
		"Email": "@body('ParseEmails')",
		"FirstName": "@body('Contact')['firstname']",
		"Gender": "@body('Contact')['_gendercode_label']",
		"IRDNo": "@body('agency')['irdnumber']",
		"MaritalStatus": "@body('Contact')['_familystatuscode_label']",
		"MiddleName": "@body('Contact')['middlename']",
		"Phones": "@body('ParseContactPhone')",
		"Surname": "@body('Contact')['lastname']",
		"Title": "@body('Contact')['title']"
	},
	"method": "post",
	"pathTemplate": {
		"parameters": {},
		"template": "/contacts/v1/people"
	},
	"subscriptionKey": "8a*******************76e"
},
"runAfter": {},
"type": "ApiManagement"
}

You can see that I’ve used the same approach for emails, addresses and phones, as all of them had the same requirements

So there you go, if you ever need to selectively provide elements in a logic app action input, this might be the way to do it. And this is just another case how Azure Functions extends Logic Apps functionality, making more complex scenarios a bit simpler.


Posted

in

,

by

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *