In pseudo code, the whole thing probably looks like
try {
// If this bit fails, we want to return a 400-Bad Request to the client.
Command<A> command = parse(httpRequest);
// We got this far, so now we pass the command we've parsed off to the
// command handler....
{
// The aggregate lookup could fail; that might be any of
// 400-Bad Request
// 404-Not Found
// 410-Gone
// ... depending on how you interpret the relationship between the
// *resource* and the *aggregate*
Aggregate<A> aggregate = Repository<A>.getById(command.id);
// A failure here is probably best reported via 409-Conflict;
// essentially to inform the user that the application state
// is stale, and should be refreshed
aggregate.execute(command);
// A failure here indicates that the command lost a data race;
// that's certainly a conflict. So if you are going to report
// an error at this point, 409-Conflict is the right way to go.
// A better choice might be to retry the command, though; after
// all, the stale version of the aggregate thought it was acceptable
// so the updated version might as well. In that case, you would
// catch this exception and reload the aggregate.
Repository<A>.save(aggregate);
}
// OK, we got through everything without a problem, so report success
reportSuccess(httpResponse);
} catch (...) {
// Possibly a single handler, or multiple handlers, depending upon
// how you design your exception hierarchy. The important thing is that
// the exception handler here knows how to translate the application
// exceptions thrown above into something suitable for http, and the
// media types being used by this endpoint.
exceptionHandler.forRequest(httpRequest).report(e, httpResponse);
}