Logic Apps – Json Schema Verify

2016, Sep 01    

Logic Apps has got a really handy trigger : Request/Response.
It provides a public URL that you can post to, and takes an optional Json Schema.  The benefit of providing a Json schema is purely that the fields defined in the schema are then accessible throughout the Logic App workflow for interaction with other actions.
This is awesome, it really makes the Visual aspect of the designer work well –  but being picky – there’s no built in validation of the Json Request against the schema you provide.

I’ve got a pretty well defined Json schema that uses

  • Required Fields
  • Typed fields (string/integer/etc)
  • Regex patterns for strings

As such i’m pretty keen to first find out if the Json in the request is actually valid.  If it’s not – I can return a 400 pretty quickly to the caller and save some valuable cash on my Logic Apps actions (Logic Apps Price Model).

The solution I went for was to wrap the Newtonsoft Json Schema library in an Azure Function.

First complication is passing in two parameters to an Azure function (the json from the Request body and the Json Schema).  Both are needed in order to perform a schema validation, and the Azure function can’t reach out to Logic Apps.  Switch to Code View in the Logic App designer and use something like this;

"body": {
          "jsondoc": "@triggerBody()",
          "schema": "@trigger().inputs.schema"
        }

Apart from that, the coding of the Azure function is pretty easy.
It’s in GitHub here https://github.com/Gordonby/AzFunctions/tree/master/JsonValidate, but here’s a snapshot of the files.

{
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "webHookType": "genericJson",
      "name": "req"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ],
  "disabled": false
}
{
  "frameworks": {
    "net46": {
      "dependencies": {
        "Newtonsoft.Json.Schema": "2.0.4"
      }
    }
  }
}
using System;
using System.Net;
using Newtonsoft.Json;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Linq;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info($"C# HTTP trigger function processed a request. RequestUri={req.RequestUri}");

    string reqbody = await req.Content.ReadAsStringAsync();
    //log.Info($"{reqbody}");
    
    if (reqbody == null ) {
        return req.CreateResponse(HttpStatusCode.OK, new {
            error = $"Request body was empty"});
    }
    else {
        try {
            JObject jsonbody = JObject.Parse(reqbody);
            //log.Info($"{jsonbody}");
            
            var jsondoc = jsonbody["jsondoc"];
            JSchema schema = JSchema.Parse(jsonbody["schema"].ToString());

            IList<string> messages; 
            bool valid = jsondoc.IsValid(schema, out messages );
            log.Info($"Validation message count : {messages.Count}");
            
            if (valid == true) {
                log.Info($"Is valid {valid}");
                return req.CreateResponse(HttpStatusCode.OK, new {schemaValid = valid});
            }  
            else {
                log.Info($"Is NOT valid {valid}");
                return req.CreateResponse(HttpStatusCode.OK, new {
                    schemaValid = valid,
                    error = $"Error validating json against schema",
                    validationMessages = messages
                });
            }
             
        }
        catch(Exception ex){
            log.Info($"{ex.ToString()}");
                    return req.CreateResponse(HttpStatusCode.OK, new {
                        error = $"Error parsing {ex.Message}"});
        }
    }
}

A simple implementation of this can be seen below.  A Request trigger which passes the body to my Function App, the Response then just relays in information provided by the output of the app.JsonSchemaValidate