{
    "href": "/post/2014/09/30/action-domain-responder-and-the-domain-payload-pattern/",
    "relId": "2014/09/30/action-domain-responder-and-the-domain-payload-pattern",
    "title": "Action-Domain-Responder and the \"Domain Payload\" Pattern",
    "author": "pmjones",
    "markup": "html",
    "tags": [
        {
            "href": "/tag/adr/",
            "relId": "adr",
            "title": "Action Domain Responder",
            "author": null,
            "created": "2020-08-17 21:07:42 UTC",
            "updated": [
                "2020-08-17 21:07:42 UTC",
                "2020-09-22 15:41:16 UTC",
                "2020-10-14 18:20:29 UTC",
                "2020-10-14 18:36:31 UTC",
                "2020-10-14 18:36:53 UTC",
                "2020-10-14 18:37:08 UTC",
                "2020-10-14 18:37:48 UTC",
                "2020-10-14 18:39:26 UTC",
                "2020-10-14 19:03:17 UTC",
                "2020-10-14 19:03:35 UTC",
                "2020-10-26 18:12:53 UTC"
            ],
            "markup": "markdown"
        },
        {
            "href": "/tag/patterns/",
            "relId": "patterns",
            "title": "Patterns",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/php/",
            "relId": "php",
            "title": "PHP",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        },
        {
            "href": "/tag/programming/",
            "relId": "programming",
            "title": "Programming",
            "author": null,
            "created": null,
            "updated": [],
            "markup": "markdown"
        }
    ],
    "created": "2014-09-30 17:16:14 UTC",
    "updated": [
        "2014-09-30 17:16:14 UTC",
        "2019-12-10 17:04:27 UTC",
        "2019-12-10 17:08:00 UTC"
    ],
    "html": "<blockquote>\n<p>tl;dr: Instead of inspecting a Domain result to determine how to present it, consider using a <a href=\"https://web.archive.org/web/20170620063845/https://vaughnvernon.co/?page_id=40\">Domain Payload Object</a> to wrap the results of Domain interaction and simulataneously indicate the status of the attempted interaction. The Domain already knows what the results mean; let it provide that information explicitly instead of attempting to re-discover it at presentation time.</p>\n</blockquote>\n<p>In <a href=\"http://pmjones.github.io/adr\">Action-Domain-Responder</a> the Action passes input to the Domain layer, which then returns some data for the Action to pass to the Responder. In simple scenarios, it might be enough for the Responder to inspect the data to determine how it should present that data. In more complex scenarios, though, it would make more sense for the Domain to pass back the data in a way that indicates the status of the data. Instead of the Responder inspecting the Domain results, the Domain should tell us what kind of results they are.</p>\n<p>For example, let\u2019s look at an example of some older code to update a Blog post. This is MVC-ish code, not ADR code; we\u2019ll refactor along the way.</p>\n<pre><code class=\"php\">&lt;?php\nclass BlogController\n{\n    // POST /blog/{id}\n    public function update($id)\n    {\n        $blog = $this-&gt;model-&gt;fetch($id);\n        if (! $blog) {\n            // 404 Not Found\n            // (no blog entry with that ID)\n            $this-&gt;response-&gt;status-&gt;set(404);\n            $this-&gt;view-&gt;setData(array('id' =&gt; $id));\n            $content = $this-&gt;view-&gt;render('not-found');\n            $this-&gt;response-&gt;body-&gt;setContent($content);\n            return;\n        }\n\n        $data = $this-&gt;request-&gt;post-&gt;get('blog');\n        if (! $blog-&gt;update($data)) {\n            // update failure, but why?\n            if (! $blog-&gt;isValid()) {\n                // 422 Unprocessable Entity\n                // (not valid)\n                $this-&gt;response-&gt;status-&gt;set(422);\n                $this-&gt;view-&gt;setData(array('blog' =&gt; $blog));\n                $content = $this-&gt;view-&gt;render('update');\n                $this-&gt;response-&gt;body-&gt;setContent($content);\n                return;\n            } else {\n                // 500 Server Error\n                // (i.e., valid data, but update failed for some other reason)\n                $this-&gt;response-&gt;status-&gt;set(500);\n                return;\n            }\n        }\n\n        // 200 OK\n        // (i.e., the update worked)\n        $this-&gt;response-&gt;status-&gt;set(200);\n        $this-&gt;view-&gt;setData(array('blog' =&gt; $blog));\n        $content = $this-&gt;view-&gt;render('update');\n        $this-&gt;response-&gt;body-&gt;setContent($content);\n    }\n}\n?&gt;\n</code></pre>\n<p>We can see that there is some amount of model work going on here (look for a blog post, attempt to update it if it exists, check for error conditions on the update attempt). There is also some amount of presentation work going on; remember, the view is not the template \u2013 the view is the <em>response</em>. So, even though the view templates are separated, the HTTP status codes are also part of the presentation, meaning that there is an insuffcient level of separation of concerns.</p>\n<p>In converting this to Action-Domain-Responder, we can pretty easily extract the model work to a Domain, and the presentation work to a Responder, resulting in something like the following. (Note that the Domain layer now adds values to the returned <code>$blog</code> entity to indicate different failure states.)</p>\n<pre><code class=\"php\">&lt;?php\nclass BlogUpdateAction\n{\n    // POST /blog/{id}\n    public function __invoke($id)\n    {\n        $data = $this-&gt;request-&gt;post-&gt;get('blog');\n        $blog = $this-&gt;domain-&gt;update($id, $data);\n        $this-&gt;responder-&gt;setData('id' =&gt; $id, 'blog' =&gt; $blog);\n        $this-&gt;responder-&gt;__invoke();\n    }\n}\n\nclass BlogUpdateResponder\n{\n    public function __invoke()\n    {\n        if (! $this-&gt;data-&gt;blog) {\n            // 404 Not Found\n            // (no blog entry with that ID)\n            $this-&gt;response-&gt;setStatus(404);\n            $this-&gt;view-&gt;setData($this-&gt;data);\n            $content = $this-&gt;view-&gt;render('not-found');\n            $this-&gt;response-&gt;body-&gt;setContent($content);\n            return;\n        }\n\n        if ($this-&gt;data-&gt;blog-&gt;updateFailed()) {\n            // 500 Server Error\n            // (i.e., valid data, but update failed for some other reason)\n            $this-&gt;response-&gt;status-&gt;set(500);\n            return;\n        }\n\n        if (! $this-&gt;data-&gt;blog-&gt;isValid()) {\n            // 422 Unprocessable Entity\n            // (invalid data submitted)\n            $this-&gt;response-&gt;setStatus(422);\n            $this-&gt;view-&gt;setData($this-&gt;data);\n            $content = $this-&gt;view-&gt;render('update');\n            $this-&gt;response-&gt;body-&gt;setContent($content);\n            return;\n        }\n\n        // 200 OK\n        // (i.e., the update worked)\n        $this-&gt;view-&gt;setData($this-&gt;data);\n        $content = $this-&gt;view-&gt;render('update');\n        $this-&gt;response-&gt;body-&gt;setContent($content);\n    }\n}\n?&gt;\n</code></pre>\n<p>But at this point we\u2019re still inspecting the Domain result to see how we should present it. This strikes me as a lot of work to determine <em>something the Domain already knows</em>.</p>\n<p>Instead of re-discovering the Domain status in the Responder, we should let the Domain tell us not only the data, but also what to think about that data. The Domain should give us an indication as to what it tried to do, and whether it succeeded or not. Then we can completely skip the inspection of the Domain results and present those results without lots of additional work.</p>\n<p>The key to doing this is something called a <a href=\"https://web.archive.org/web/20170620063845/https://vaughnvernon.co/?page_id=40\">Domain Payload Object</a>. (Initially I called this a \u201cDomain Result\u201d but my recent reading of Vernon\u2019s <a href=\"http://www.amazon.com/Implementing-Domain-Driven-Design-Vaughn-Vernon/dp/0321834577\">Implementing Domain Driven Design</a> revealed the term to me. I love finding the right word for a concept!)</p>\n<p>With a Domain Payload, we wrap the Domain results in an object that carries those results for us. We can then extend the semantics of the Domain Payload to tell us <em>what kind</em> of payload it carries. Something as simple as the class name of the Domain Payload can give us that information.</p>\n<p>In the <a href=\"https://github.com/pmjones/adr/tree/master/example-code\">ADR example code</a> we will find <a href=\"https://github.com/pmjones/adr/tree/master/example-code/Domain/Payload\">a series of Domain Payload objects</a>. While these map closely to HTTP response codes for simplicity\u2019s sake, other Domains are very likely to have different kinds of payload statuses.  The point is that each Payload object explicitly tells us what the results indicate: entity not found, invalid data in the entity, database error, successful update, and so on.</p>\n<p>The <a href=\"https://github.com/pmjones/adr/blob/master/example-code/Web/Blog/Action/BlogUpdateAction.php\">BlogUpdateAction</a> remains straightforward. However, the <a href=\"https://github.com/pmjones/adr/blob/master/example-code/Domain/Blog/BlogService.php\">example BlogService</a>\u2018s <a href=\"https://github.com/pmjones/adr/blob/master/example-code/Domain/Blog/BlogService.php#L121-L166\">update() method</a> now does all the update work, <em>and</em> it wraps all returned results in a Domain Payload that indicates the result status.</p>\n<p>Finally, the <a href=\"https://github.com/pmjones/adr/blob/master/example-code/Web/Blog/Responder/BlogUpdateResponder.php\">BlogUpdateResponder</a>, which itself extends an <a href=\"https://github.com/pmjones/adr/blob/master/example-code/Web/AbstractResponder.php\">AbstractResponder</a>, can match a Domain Payload class name to a method that presents the payload results.</p>\n<p>Voila: no more inspection of the results to figure out presentation. We let the Domain tell us what it tried to do and whether it worked or not (and what the cause of the failure was, if any). At the presentation layer, our Responder can honor (or ignore) that information at its convenience.</p>\n<hr>\n<p class=\"reddit-links\">Read the Reddit discussion about this post <a href=\"https://www.reddit.com/r/PHP/comments/2hwmx2/actiondomainresponder_and_the_domain_payload/\">here</a>.</p>\n"
}
