Archive

Archive for January, 2021

Run #postman collections in C# (.NET Core) hosted on AWS Lambda

Major Caveat, this is very much a work in progress, that I hope to complete one day, or that someone will complete, and be nice enough to share the code via a pull request.

But, here’s the repo on github: https://github.com/infiniteloopltd/PostmanSharp

The motivation behind this, was a way to define a Javascript library that could be used to execute Postman collections. Javascript can’t call most APIs, apart from those with CORS enabled, or hosted on the same server. However, Postman offers a nice way to define an API, and export that definition as a Postman collection.

So, what I did, was created a C# library that interprets a Postman collection, and carries out the calling of that API, using variables passed in. So far, It only does HTTP GET requests, but it could be expanded easily.

So, let’s start off with the library; which is defined as follows –

public class Postman
{
	private JObject postmanCollection;
	public Postman(string collection)
	{
	    postmanCollection = JObject.Parse(collection);
	}

	public string Execute(string function, string variables)
	{
	    var item = postmanCollection["item"].FirstOrDefault(
		j => j["name"] + "" == function);
	    if (item == null) throw new ArgumentException("function not recognized");
	    var request = item["request"];
	    var method = request["method"] + "";
	    if (method != "GET") 
		throw new NotImplementedException("Only HTTP GET is currently supported");
	    if (request["header"] is JArray headers && headers.Count > 0) 
		throw new NotImplementedException("HTTP Headers are not yet supported");
	    var url = request["url"]["raw"] + "";
	    var jVariables = JObject.Parse(variables);
	    foreach (var (key,value) in jVariables)
	    {
		url = url.Replace("{{" + key + "}}", value+"");
	    }
	    using var web = new WebClient {Encoding = Encoding.UTF8};
	    var result = web.DownloadString(url);
	    return result;
	}
}

You could use this from a console app, to call a postman-defined API, but to make it more interesting, I created an AWS Lambda function, and configured my API gateway to permit CORS with the following code:

public string FunctionHandler(LambdaRequest request, ILambdaContext context)
{
    string result;
    try
    {
	LambdaLogger.Log("FunctionHandler called");
	LambdaLogger.Log(request.body);
	if (!request.body.StartsWith("{"))
	{
	    request.body = Encoding.UTF8.GetString(Convert.FromBase64String(request.body));
	}
	var jsonBody = JObject.Parse(request.body);
	var collection = jsonBody["collection"] + "";
	var function = jsonBody["function"] + "";
	var variables = jsonBody["variables"] + "";
	var postman = new Postman(collection);
	result = postman.Execute(function, variables);
    }
    catch (Exception ex)
    {
	result = ex.ToString();
    }
    LambdaLogger.Log(result);
    return result; 
}

Where LambdaRequest is defined simply as:

public class LambdaRequest
{
    public string body { get; set; }
}

Now, once the Lambda is uploaded to AWS, and an API gateway, with CORS enabled is set up, then I defined my Javascript class as follows (actual url omitted)

class Postman
{
	constructor(collection)
	{
		this.collection = collection;
	}

	execute(postmanFunction, variables)
	{
		var url = "https://xxxxx.amazonaws.com/default/Postman";
		return this.postData(url, 
			{
			 "collection" : this.collection, 
			 "function" : postmanFunction, 
			 "variables" : JSON.stringify(variables)
			});
	}

	async postData(url = '', data = {}) {
	  const response = await fetch(url, {
		method: 'POST', 
		mode: 'cors', 
		body: JSON.stringify(data) 
	  });
	  return response.json(); 
	}

}

Then, it’s called something like this in the page;

var collection = ... 
var postman = new Postman(collection);
var variables = {
	address : "Dublin, Ireland"
};
postman.execute("Geolocation",variables).then( data => {
	console.log(data);
	var pos = data.Response.View[0].Result[0].Location.NavigationPosition[0];
	alert(pos.Latitude + "," + pos.Longitude);
});

Categories: Uncategorized