New Http support for Command/Queries in Griffin Framework

I’ve just pushed a new CqsHttpListener and CqsHttpClient to Griffin.Framework. With it you can host a small HTTP server within your application to be able to receive Command/query objects from your client applications.

Invoking a command

To get started let’s just define a small command:

public class RaiseHands : Command
{
    public string Reason { get; set; }
}

The command is invoked client side by using our simple http client:

var client = new CqsHttpClient("http://localhost:1234");
await client.ExecuteAsync(new RaiseHands {Reason = "all YOUR base"});

That’s it.

Processing the command

To be able to execute the command we need to start by defining a handler:

public class RaiseHandsHandler : ICommandHandler<RaiseHands>
{
    public async Task ExecuteAsync(RaiseHands command)
    {
        //TODO: Do something useful
    }
}

Once done we also need to be able to invoke it. In Griffin.Framework we have two options. The inversion of control container support or the simple support. For this exercise let’s use the simple support:

//can be an ioc bus too.
var commandBus = new SimpleCommandBus();
commandBus.Register(Assembly.GetExecutingAssembly());

//takes care of execution
var processor = new CqsMessageProcessor {CommandBus = commandBus};

//receive through HTTP
var server = new CqsHttpListener(processor);
server.Start(new IPEndPoint(IPAddress.Loopback, 1234));

So what the server do is to translate the incoming command object (serialized as JSON), find the handler and execute it.

Using a regular HTTP client

The cool thing is that the server supports regular HTTP clients too. Just make sure that the command is represented by a valid JSON string.

Here is an example:

var client = new HttpClient();
var content = new StringContent(@"{ ""Reason"": ""So simple!"" }", 
                               Encoding.UTF8, 
                               "application/json");
content.Headers.Add("X-Cqs-Name", "RaiseHands");
await client.PutAsync("http://localhost:1234", content);

The problem with JSON is that there is no way of identifying if the supplied string is a command or which command that is for that matter. That’s why the X-Cqs-Name header is included.

At server side we also need to index all commands/queries. You can do that object by object or by scanning an assembly for all command/query objects.

var server = new CqsHttpListener(processor);

//map a single object
server.Map(typeof(GetUsers));

//map all cqs objects in the specified assembly
server.ScanAssembly(Assembly.GetExecutingAssembly());

//run
server.Start(new IPEndPoint(IPAddress.Loopback, 0));

The HTTP approach also allows you to invoke CQS objects directly from the client side using AJAX (or web sockets).

Summary

Everything works for commands, queries, request/reply and application events. I’ll push a new nuget package as soon as I’ve created more tests for the different CQS object types.

Code as github.

I’ll probably create a package for ASP.NET MVC5 too and a Griffin WebSocket host in a near future.

  • Your framework seems powerful and thought provoking. With CqsHttpClient, do you simply assume that all traffic is an HTTP POST or PUT? For example, if you execute a Command that will result in a “delete” on the server, is that command sent as an HTTP POST anyway? And how do you handle versioning of commands?

    • I’m only using a few verbs as in CQS you either fetch something or you update something. imho DELETE would not work, A Command in the pattern definition (Command/Query separation) makes no difference on what are being changed (i.e. delete is just considered to be a change action). Commands should also be considered as wrapping an entire user story and not a single action on a specific entity.

      I’ve updated the client so that queries can be serialized as query string arguments. By doing so they can be sent as HTTP GET (as GET requests should have no HTTP body).

      • In addition to queries represented through a query string, instead of a X-cqs-name header, why not also identify commands through a URI path segment rather than the X-cqs-header? In other words, is there any reason the X-cqs-header can’t be eliminated entirely?