<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text">Blog entries tagged rest :: mwop.net</title>
  <updated>2018-09-19T08:10:00-05:00</updated>
  <generator uri="https://getlaminas.org" version="2">Laminas_Feed_Writer</generator>
  <link rel="alternate" type="text/html" href="https://mwop.net/blog/tag/rest"/>
  <link rel="self" type="application/atom+xml" href="https://mwop.net/blog/tag/rest/atom.xml"/>
  <id>https://mwop.net/blog/tag/rest</id>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Notes on GraphQL]]></title>
    <published>2018-07-18T17:05:00-05:00</published>
    <updated>2018-09-19T08:10:00-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2018-07-18-graphql.html"/>
    <id>https://mwop.net/blog/2018-07-18-graphql.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>The last week has been my first foray into GraphQL, using the
<xhtml:a href="https://developer.github.com/v4/">GitHub GraphQL API</xhtml:a>
endpoints. I now have Opinions<xhtml:sup>TM</xhtml:sup>.</xhtml:p>
<xhtml:p>The promise is fantastic: query for everything you need, but
nothing more. Get it all in one go.</xhtml:p>
<xhtml:p>But the reality is somewhat... different.</xhtml:p>
<xhtml:p>What I found was that you end up with a lot of garbage data
structures that you then, on the client side, need to decipher and
massage, unpacking edges, nodes, and whatnot. I ended up having to
do almost a dozen <xhtml:code>array_column()</xhtml:code>,
<xhtml:code>array_map()</xhtml:code>, and <xhtml:code>array_reduce()</xhtml:code>
operations on the returned data to get a structure I can actually
use.</xhtml:p>
<xhtml:p>The final data I needed looked like this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">[
  {
    <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"zendframework/zend-expressive"</xhtml:span>,
    <xhtml:span class="hljs-string">"tags"</xhtml:span>: [
      {
        <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"3.0.2"</xhtml:span>,
        <xhtml:span class="hljs-string">"date"</xhtml:span>: <xhtml:span class="hljs-string">"2018-04-10"</xhtml:span>
      }
    ]
  }
]
</xhtml:code></xhtml:pre>
<xhtml:p>To fetch it, I needed a query like the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">query showOrganizationInfo(
  $organization:<xhtml:span class="hljs-built_in">String</xhtml:span>!
  $cursor:<xhtml:span class="hljs-built_in">String</xhtml:span>!
) {
  organization(login:$organization) {
    repositories(first: <xhtml:span class="hljs-number">100</xhtml:span>, <xhtml:span class="hljs-attr">after</xhtml:span>: $cursor) {
      pageInfo {
        startCursor
        hasNextPage
        endCursor
      }
      nodes {
        nameWithOwner
        <xhtml:span class="hljs-attr">tags</xhtml:span>:refs(refPrefix: <xhtml:span class="hljs-string">"refs/tags/"</xhtml:span>, <xhtml:span class="hljs-attr">first</xhtml:span>: <xhtml:span class="hljs-number">100</xhtml:span>, <xhtml:span class="hljs-attr">orderBy</xhtml:span>:{<xhtml:span class="hljs-attr">field</xhtml:span>:TAG_COMMIT_DATE, <xhtml:span class="hljs-attr">direction</xhtml:span>:DESC}) {
          edges {
            <xhtml:span class="hljs-attr">tag</xhtml:span>: node {
              name
              target {
                ... on Commit {
                  pushedDate
                }
                ... on Tag {
                  tagger {
                    date
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Which gave me data like the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
  <xhtml:span class="hljs-string">"data"</xhtml:span>: {
    <xhtml:span class="hljs-string">"organization"</xhtml:span>: {
      <xhtml:span class="hljs-string">"repositories: {
        "</xhtml:span>pageInfo<xhtml:span class="hljs-string">": {
          "</xhtml:span>startCursor<xhtml:span class="hljs-string">": "</xhtml:span>...<xhtml:span class="hljs-string">",
          "</xhtml:span>hasNextPage<xhtml:span class="hljs-string">": true,
          "</xhtml:span>endCursor<xhtml:span class="hljs-string">": "</xhtml:span>...<xhtml:span class="hljs-string">"
        },
        "</xhtml:span>nodes<xhtml:span class="hljs-string">": [
          {
            "</xhtml:span>nameWithOwner<xhtml:span class="hljs-string">": "</xhtml:span>zendframework/zend-expressive<xhtml:span class="hljs-string">",
            "</xhtml:span>tags<xhtml:span class="hljs-string">": {
              "</xhtml:span>edges<xhtml:span class="hljs-string">": [
                "</xhtml:span>tag<xhtml:span class="hljs-string">": {
                  "</xhtml:span>name<xhtml:span class="hljs-string">": "</xhtml:span><xhtml:span class="hljs-number">3.0</xhtml:span><xhtml:span class="hljs-number">.2</xhtml:span><xhtml:span class="hljs-string">",
                  "</xhtml:span>target<xhtml:span class="hljs-string">": {
                    "</xhtml:span>tagger<xhtml:span class="hljs-string">": {
                      "</xhtml:span>date<xhtml:span class="hljs-string">": "</xhtml:span><xhtml:span class="hljs-number">2018</xhtml:span><xhtml:span class="hljs-number">-04</xhtml:span><xhtml:span class="hljs-number">-10</xhtml:span><xhtml:span class="hljs-string">"
                    }
                  }
                }
              ]
            }
          }
        ]
      }
    }
  }
}
</xhtml:span></xhtml:code></xhtml:pre>
<xhtml:p>How did I discover how to create the query? I'd like to say it
was by reading the docs. I really would. But these gave me almost
zero useful examples, particularly when it came to pagination,
ordering results sets, or what those various "nodes" and "edges"
bits were, or why they were necessary. (I eventually found the
information, but it's still rather opaque as an end-user.)</xhtml:p>
<xhtml:p>Additionally, see that <xhtml:code>pageInfo</xhtml:code> bit? This brings me
to my next point: pagination sucks, particularly if it's not at the
top-level. You can only fetch 100 items at a time from any given
node in the GitHub GraphQL API, which means pagination. And I have
yet to find a client that will detect pagination data in results
and auto-follow them. Additionally, the "after" property had to be
something valid... but there were no examples of what a valid value
would be. I had to resort to StackOverflow to find an example, and
I still don't understand why it works.</xhtml:p>
<xhtml:blockquote>
<xhtml:p>I get why clients cannot unfurl pagination, as pagination data
could appear <xhtml:em>anywhere</xhtml:em> in the query. However, it hit me
hard, as I thought I had a complete set of data, only to discover
around half of it was missing once I finally got the processing
correct.</xhtml:p>
</xhtml:blockquote>
<xhtml:p>If any items further down the tree <xhtml:em>also</xhtml:em> require
pagination, you're in for some real headaches, as you then have to
fetch paginated sets depth-first.</xhtml:p>
<xhtml:p>So, while GraphQL promises fewer round trips and exactly the
data you need, my experience so far is:</xhtml:p>
<xhtml:ul>
<xhtml:li>
<xhtml:p>I end up having to be very careful about structuring my queries,
paying huge attention to pagination potential, and often sending
multiple queries ANYWAYS. A well-documented REST API is often far
easier to understand and work with immediately.</xhtml:p>
</xhtml:li>
<xhtml:li>
<xhtml:p>I end up doing MORE work client-side to make the data I receive
back USEFUL. This is because the payload structure is based on the
query structure and the various permutations you need in order to
get at the data you need. Again, a REST API usually has a single,
well-documented payload, making consumption far easier.</xhtml:p>
</xhtml:li>
</xhtml:ul>
<xhtml:p>I'm sure I'm probably mis-using GraphQL, or missing a number of
features to make this stuff easier, but so far, I'm left wishing I
could just have a number of useful REST endpoints that I can hit
consistently in order to aggregate the data I need.</xhtml:p>
<xhtml:blockquote>
<xhtml:p>Before anybody suggests it, yes, I am <xhtml:em>very</xhtml:em> aware that
GitHub also offers a REST API, and the v3 API has endpoints for
most of what I needed. However, I had to rely on tags, not
releases, as not all of our tags have associated releases. However,
the data returned for tags does not include the commit date; for
that, you need to fetch the associated commit, and then the date
may be under either the <xhtml:code>author</xhtml:code> or the
<xhtml:code>committer</xhtml:code>. This approach would have meant literally
thousands of calls to get the data I need, which would have had me
hitting rate limits, and potentially taking hours to complete.</xhtml:p>
<xhtml:p>My point: perhaps instead of GraphQL, aggregating a bit more
data in REST resources (e.g., including commit data with tags), or
providing endpoints that allow merging specific resource types
could have solved the problem easily. This is where having a
developer relations team that finds out what data
<xhtml:em>consumers</xhtml:em> are needing comes in handy, instead of simply
mandating <xhtml:em>graphql all the things</xhtml:em> to allow infinite
flexibility (and the frustrations of such flexibility, both for the
API developer and consumer).</xhtml:p>
</xhtml:blockquote>
<xhtml:h3>Updates</xhtml:h3>
<xhtml:ul>
<xhtml:li>2018-09-19: syntax highlighting fixes.</xhtml:li>
</xhtml:ul>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2018-07-18-graphql.html">Notes on
GraphQL</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2018-07-18T17:05:00-05:00">18 July 2018</xhtml:time> on
<xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Apigility: Using RPC with HAL]]></title>
    <published>2014-03-26T15:30:00-05:00</published>
    <updated>2014-03-26T15:30:00-05:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2014-03-26-apigility-rpc-with-hal.html"/>
    <id>https://mwop.net/blog/2014-03-26-apigility-rpc-with-hal.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>A few days ago, we <xhtml:a href="http://bit.ly/ag-1-beta1">released
our first beta of Apigility</xhtml:a>. We've started our documentation
effort now, and one question has arisen a few times that I want to
address: How can you use Hypermedia Application Language (HAL) in
RPC services?</xhtml:p>
<xhtml:h2>HAL?</xhtml:h2>
<xhtml:p><xhtml:a href="http://tools.ietf.org/html/draft-kelly-json-hal-06">Hypermedia
Application Language</xhtml:a> is an IETF proposal for how to represent
resources and their relations within APIs. Technically, it provides
two mediatypes, <xhtml:code>application/hal+json</xhtml:code> and
<xhtml:code>application/hal+xml</xhtml:code>; however, Apigility only provides
the JSON variant.</xhtml:p>
<xhtml:p>The important things to know about HAL are:</xhtml:p>
<xhtml:ul>
<xhtml:li>
<xhtml:p>It provides a standard way of describing relational links. All
relational links are under a <xhtml:code>_links</xhtml:code> property of the
resource. That property is an object. Each property of that object
is a link relation; the value of each link relation is an object
(or array of such objects) describing the link that must minimally
contain an <xhtml:code>href</xhtml:code> proerty. The link object itself can
contain some additional metadata, such as a mediatype, a name
(useful for differentiating between multiple link objects assigned
to the same relation).</xhtml:p>
<xhtml:p>While not required, the specification recommends resources
contain a "self" relational link, indicating the canonical location
for the resource. This is particularly useful when we consider
embedding (the next topic).</xhtml:p>
<xhtml:p>Sound hard? It's not:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {
            <xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"/blog/2014-03-26-apigility-rpc-with-hal"</xhtml:span>
        }
    }
}
</xhtml:code></xhtml:pre></xhtml:li>
<xhtml:li>
<xhtml:p>Besides link relations, HAL also provides a standard way of
describing <xhtml:em>embedded resources</xhtml:em>. An embedded resource is any
other resource you can address via your API, and, as such, would be
structured as a HAL resource — in other words, it would have a
<xhtml:code>_links</xhtml:code> property with relational links. Essentially,
any property of the resource you're returning that can itself be
addressed via the URI must be <xhtml:em>embedded</xhtml:em> in the resource.
This is done via the property <xhtml:code>_embedded</xhtml:code>.</xhtml:p>
<xhtml:p>Like <xhtml:code>_links</xhtml:code>, <xhtml:code>_embedded</xhtml:code> is an object.
Each key in the object is the local name by which the resource
refers to the embedded resource. The value of such keys can either
be HAL resources or <xhtml:em>arrays</xhtml:em> of HAL resources; in fact, this
is how <xhtml:em>collections</xhtml:em> are represented in HAL!</xhtml:p>
<xhtml:p>As examples:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {
            <xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"/blog/2014-03-26-apigility-rpc-with-hal"</xhtml:span>
        }
    },
    <xhtml:span class="hljs-string">"_embedded"</xhtml:span>: {
        <xhtml:span class="hljs-string">"author"</xhtml:span>: {
            <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                <xhtml:span class="hljs-string">"self"</xhtml:span>: {
                    <xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"/blog/author/matthew"</xhtml:span>
                }
            },
            <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"matthew"</xhtml:span>,
            <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"Matthew Weier O'Phinney"</xhtml:span>,
            <xhtml:span class="hljs-string">"url"</xhtml:span>: <xhtml:span class="hljs-string">"http://mwop.net"</xhtml:span>
        },
        <xhtml:span class="hljs-string">"tags"</xhtml:span>: [
            {
                <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                    <xhtml:span class="hljs-string">"self"</xhtml:span>: {
                        <xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"/blog/tag/php"</xhtml:span>
                    }
                },
                <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"php"</xhtml:span>
            },
            {
                <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                    <xhtml:span class="hljs-string">"self"</xhtml:span>: {
                        <xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"/blog/tag/rest"</xhtml:span>
                    }
                },
                <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"rest"</xhtml:span>
            }
        ]
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>The example above shows two embedded resources. The first is the
author; the second, a collection of tags. Note that <xhtml:em>every</xhtml:em>
object under <xhtml:code>_embedded</xhtml:code> is a HAL object!</xhtml:p>
<xhtml:p>You can go quite far with this — you can also have embedded
resources inside your embedded resources, arbitrarily deep.</xhtml:p>
</xhtml:li>
</xhtml:ul>
<xhtml:h2>RPC?</xhtml:h2>
<xhtml:p>RPC stands for Remote Procedure Call, and, when describing a web
API, is usually used to describe a web service that publishes
multiple method calls at a single URI using only <xhtml:code>POST</xhtml:code>;
XML-RPC and SOAP are the usual suspects.</xhtml:p>
<xhtml:p>In Apigility, we use the term RPC in a much looser sense; we use
it to describe one-off services: actions like "authenticate," or
"notify," or "register" would all make sense here. They are actions
that usually only need to respond to a single HTTP method, and
which may or may not describe a "thing", which is what we usually
consider a "resource" when discussing REST terminology.</xhtml:p>
<xhtml:p>That said: what if what we want to return from the RPC call
<xhtml:em>are</xhtml:em> REST resources?</xhtml:p>
<xhtml:h2>Returning HAL from RPC Services</xhtml:h2>
<xhtml:p>In order to return HAL from RPC services, we need to understand
(a) how Content Negotiation works, and (b) what needs to be
returned in order for the HAL renderer to be able to create a
representation.</xhtml:p>
<xhtml:p>For purposes of this example, I'm positing a
<xhtml:code>RegisterController</xhtml:code> as an RPC service that, on success,
is returning a <xhtml:code>User</xhtml:code> object that I want rendered as a
HAL resource.</xhtml:p>
<xhtml:p>The <xhtml:a href="https://github.com/zfcampus/zf-content-negotiation">zf-content-negotiation</xhtml:a>
module takes care of content negotiation for Apigility. It
introspects the <xhtml:code>Accept</xhtml:code> header in order to determine if
we can return a representation, and then, if it can, will cast any
<xhtml:code>ZF\ContentNegotiation\ViewModel</xhtml:code> returned from a
controller to the appropriate view model for the representation.
From there, a renderer will pick up the view model and do what
needs to be done.</xhtml:p>
<xhtml:p>So, the first thing we have to do is return
<xhtml:code>ZF\ContentNegotiation\ViewModel</xhtml:code> instances from our
controller.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractActionController</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">ZF</xhtml:span>\<xhtml:span class="hljs-title">ContentNegotiation</xhtml:span>\<xhtml:span class="hljs-title">ViewModel</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">RegisterController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractActionController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">registerAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-comment">/* ... do some work ... get a user ... */</xhtml:span>
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">new</xhtml:span> ViewModel(<xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-string">'user'</xhtml:span> =&gt; $user));
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>The <xhtml:a href="https://github.com/zfcampus/zf-hal">zf-hal</xhtml:a>
module in Apigility creates the actual HAL representations.
<xhtml:code>zf-hal</xhtml:code> looks for a "payload" variable in the view
model, and expects that value to be either a
<xhtml:code>ZF\Hal\Entity</xhtml:code> (single item) or
<xhtml:code>ZF\Hal\Collection</xhtml:code>. When creating an
<xhtml:code>Entity</xhtml:code> object, you need the object being represented,
as well as the identifier. So, let's update our return value.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractActionController</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">ZF</xhtml:span>\<xhtml:span class="hljs-title">ContentNegotiation</xhtml:span>\<xhtml:span class="hljs-title">ViewModel</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">ZF</xhtml:span>\<xhtml:span class="hljs-title">Hal</xhtml:span>\<xhtml:span class="hljs-title">Entity</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">RegisterController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractActionController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">registerAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-comment">/* ... do some work
         * ... get a $user
         * ... assume we have also now have an $id
         */</xhtml:span>
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">new</xhtml:span> ViewModel(<xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-string">'payload'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'user'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">new</xhtml:span> Entity($user, $id),
        )));
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p><xhtml:code>zf-hal</xhtml:code> contains what's called a "metadata map".
This is a map of classes to information on how <xhtml:code>zf-hal</xhtml:code>
should render them: what route to use, what additional relational
links to inject, how to serialize the object, what field represents
the identifier, etc.</xhtml:p>
<xhtml:p>In most cases, you will have likely already defined a REST
service for the resource you want to return from the RPC service,
in which case you will be done. However, if you want, you can go in
and manually configure the metadata map in your API module's
<xhtml:code>config/module.config.php</xhtml:code> file:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
    <xhtml:span class="hljs-string">'zf-hal'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'metadata_map'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'User'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
                <xhtml:span class="hljs-string">'route_name'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'api.rest.user'</xhtml:span>,
                <xhtml:span class="hljs-string">'entity_identifier_name'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'username'</xhtml:span>,
                <xhtml:span class="hljs-string">'route_identifier_name'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'user_id'</xhtml:span>,
                <xhtml:span class="hljs-string">'hydrator'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'Zend\Stdlib\Hydrator\ObjectProperty'</xhtml:span>,
            ),
        ),
    ),
);
</xhtml:code></xhtml:pre>
<xhtml:p>Finally, we need to make sure that the service is configured to
actually return HAL. We can do this in the admin if we want. Find
the "Content Negotiation" section of the admin, and the "Content
Negotiation Selector" item, and set that to "HalJson"; don't forget
to save! Alternately, you can do this manually in the API module's
<xhtml:code>config/module.config.php</xhtml:code> file, under the
<xhtml:code>zf-content-negotiation</xhtml:code> section:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
    <xhtml:span class="hljs-string">'zf-content-negotiation'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'controllers'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
            <xhtml:span class="hljs-string">'RegisterController'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'HalJson'</xhtml:span>,
        ),
        <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
    ),
);
</xhtml:code></xhtml:pre>
<xhtml:p>Once your changes are complete, when you make a successful
request to the URI for your "register" RPC service, you'll receive
a HAL response pointing to the canonical URI for the user resource
created!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2014-03-26-apigility-rpc-with-hal.html">Apigility:
Using RPC with HAL</xhtml:a> was originally published <xhtml:time class="dt-published" datetime="2014-03-26T15:30:00-05:00">26 March
2014</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by
<xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew
Weier O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[RESTful APIs with ZF2, Part 3]]></title>
    <published>2013-02-25T06:29:00-06:00</published>
    <updated>2013-02-25T06:29:00-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2013-02-25-restful-apis-with-zf2-part-3.html"/>
    <id>https://mwop.net/blog/2013-02-25-restful-apis-with-zf2-part-3.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>In my <xhtml:a href="/blog/2013-02-11-restful-apis-with-zf2-part-1.html">previous</xhtml:a>
<xhtml:a href="/blog/2013-02-13-restful-apis-with-zf2-part-2.html">posts</xhtml:a>, I
covered basics of JSON hypermedia APIs using Hypermedia Application
Language (HAL), and methods for reporting errors, including
API-Problem and <xhtml:code>vnd.error</xhtml:code>.</xhtml:p>
<xhtml:p>In this post, I'll be covering <xhtml:em>documenting</xhtml:em> your API —
techniques you can use to indicate what HTTP operations are
allowed, as well as convey the full documentation on what endpoints
are available, what they accept, and what you can expect them to
return.</xhtml:p>
<xhtml:p>While I will continue covering general aspects of RESTful APIs
in this post, I will also finally introduce several ZF2-specific
techniques.</xhtml:p>
<xhtml:h2>Why Document?</xhtml:h2>
<xhtml:p>If you're asking this question, you've either never consumed
software, or your software is perfect and self-documenting. I
frankly don't believe either one.</xhtml:p>
<xhtml:p>In the case of APIs, those consuming the API need to know how to
use it.</xhtml:p>
<xhtml:ul>
<xhtml:li>What endpoints are available? Which operations are available
for each endpoint?</xhtml:li>
<xhtml:li>What does each endpoint expect as a payload during the
request?</xhtml:li>
<xhtml:li>What can you expect as a payload in return?</xhtml:li>
<xhtml:li>How will errors be communicated?</xhtml:li>
</xhtml:ul>
<xhtml:p>While the promise of hypermedia APIs is that each response tells
you the next steps available, you still, somewhere along the way,
need more information — what payloads look like, which HTTP verbs
should be used, and more. If you're <xhtml:strong>not</xhtml:strong>
documenting your API, you're "doing it wrong."</xhtml:p>
<xhtml:h2>Where Should Documentation Live?</xhtml:h2>
<xhtml:p>This is the much bigger question.</xhtml:p>
<xhtml:p>Of the questions I raised above, detailing what should be
documented, there are two specific types. When discussing what
operations are available, we have a technical solution in the form
of the <xhtml:code>OPTIONS</xhtml:code> method and its counterpart, the
<xhtml:code>Allow</xhtml:code> header. Everything else falls under end-user
documentation.</xhtml:p>
<xhtml:h2>OPTIONS</xhtml:h2>
<xhtml:p>The HTTP specification details the <xhtml:code>OPTIONS</xhtml:code> method
as idempotent, non-cacheable, and for use in detailing what
operations are available for the given resource specified by the
request URI. It makes specific mention of the <xhtml:code>Allow</xhtml:code>
header, but does not limit what is returned for requests made via
this method.</xhtml:p>
<xhtml:p>The <xhtml:code>Allow</xhtml:code> header details the allowed HTTP methods
for the given resource.</xhtml:p>
<xhtml:p>Used in combination, you make an <xhtml:code>OPTIONS</xhtml:code> request to
a URI, and it should return a response containing an
<xhtml:code>Allow</xhtml:code> header; from that header value, you then know
what other HTTP methods can be made to that URI.</xhtml:p>
<xhtml:p>What this tells us is that our RESTful endpoint should do the
following:</xhtml:p>
<xhtml:ul>
<xhtml:li>When an <xhtml:code>OPTIONS</xhtml:code> request is made, return a response
with an <xhtml:code>Allow</xhtml:code> header that has a list of the available
HTTP methods allowed.</xhtml:li>
<xhtml:li>For any HTTP method we do <xhtml:em>not</xhtml:em> allow, we should return
a "405 Not Allowed" response.</xhtml:li>
</xhtml:ul>
<xhtml:p>These are fairly easy to accomplish in ZF2. <xhtml:em>(See? I promised
I'd get to some ZF2 code in this post!)</xhtml:em></xhtml:p>
<xhtml:p>When creating RESTful endpoints in ZF2, I recommend using
<xhtml:code>Zend\Mvc\Controller\AbstractRestfulController</xhtml:code>. This
controller contains an <xhtml:code>options()</xhtml:code> method which you can
use to respond to an <xhtml:code>OPTIONS</xhtml:code> request. As with any ZF2
controller, returning a response object will prevent rendering and
bubble out immediately so that the response is returned.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">namespace</xhtml:span> <xhtml:span class="hljs-title">My</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">FooController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">options</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $response = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getResponse();
        $headers  = $response-&gt;getHeaders();

        <xhtml:span class="hljs-comment">// If you want to vary based on whether this is a collection or an</xhtml:span>
        <xhtml:span class="hljs-comment">// individual item in that collection, check if an identifier from</xhtml:span>
        <xhtml:span class="hljs-comment">// the route is present</xhtml:span>
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;params()-&gt;fromRoute(<xhtml:span class="hljs-string">'id'</xhtml:span>, <xhtml:span class="hljs-keyword">false</xhtml:span>)) {
            <xhtml:span class="hljs-comment">// Allow viewing, partial updating, replacement, and deletion</xhtml:span>
            <xhtml:span class="hljs-comment">// on individual items</xhtml:span>
            $headers-&gt;addHeaderLine(<xhtml:span class="hljs-string">'Allow'</xhtml:span>, implode(<xhtml:span class="hljs-string">','</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(
                <xhtml:span class="hljs-string">'GET'</xhtml:span>,
                <xhtml:span class="hljs-string">'PATCH'</xhtml:span>,
                <xhtml:span class="hljs-string">'PUT'</xhtml:span>,
                <xhtml:span class="hljs-string">'DELETE'</xhtml:span>,
            )));
            <xhtml:span class="hljs-keyword">return</xhtml:span> $response;
        }

        <xhtml:span class="hljs-comment">// Allow only retrieval and creation on collections</xhtml:span>
        $headers-&gt;addHeaderLine(<xhtml:span class="hljs-string">'Allow'</xhtml:span>, implode(<xhtml:span class="hljs-string">','</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'GET'</xhtml:span>,
            <xhtml:span class="hljs-string">'POST'</xhtml:span>,
        )));
        <xhtml:span class="hljs-keyword">return</xhtml:span> $response;
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>The next trick is returning the 405 response if an invalid
option is used. For this, you can create a listener in your
controller, and wire it to listen at higher-than-default priority.
As an example:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">namespace</xhtml:span> <xhtml:span class="hljs-title">My</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">EventManager</xhtml:span>\<xhtml:span class="hljs-title">EventManagerInterface</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">FooController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $allowedCollectionMethods = <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'GET'</xhtml:span>,
        <xhtml:span class="hljs-string">'POST'</xhtml:span>,
    );

    <xhtml:span class="hljs-keyword">protected</xhtml:span> $allowedResourceMethods = <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'GET'</xhtml:span>,
        <xhtml:span class="hljs-string">'PATCH'</xhtml:span>,
        <xhtml:span class="hljs-string">'PUT'</xhtml:span>,
        <xhtml:span class="hljs-string">'DELETE'</xhtml:span>,
    );

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">setEventManager</xhtml:span><xhtml:span class="hljs-params">(EventManagerInterface $events)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">parent</xhtml:span>::setEventManager($events);
        $events-&gt;attach(<xhtml:span class="hljs-string">'dispatch'</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-keyword">$this</xhtml:span>, <xhtml:span class="hljs-string">'checkOptions'</xhtml:span>), <xhtml:span class="hljs-number">10</xhtml:span>);
    }

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">checkOptions</xhtml:span><xhtml:span class="hljs-params">($e)</xhtml:span>
    </xhtml:span>{
        $matches  = $e-&gt;getRouteMatch();
        $response = $e-&gt;getResponse();
        $request  = $e-&gt;getRequest();
        $method   = $request-&gt;getMethod();

        <xhtml:span class="hljs-comment">// test if we matched an individual resource, and then test</xhtml:span>
        <xhtml:span class="hljs-comment">// if we allow the particular request method</xhtml:span>
        <xhtml:span class="hljs-keyword">if</xhtml:span> ($matches-&gt;getParam(<xhtml:span class="hljs-string">'id'</xhtml:span>, <xhtml:span class="hljs-keyword">false</xhtml:span>)) {
            <xhtml:span class="hljs-keyword">if</xhtml:span> (!in_array($method, <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;allowedResourceMethods)) {
                $response-&gt;setStatusCode(<xhtml:span class="hljs-number">405</xhtml:span>);
                <xhtml:span class="hljs-keyword">return</xhtml:span> $response;
            }
            <xhtml:span class="hljs-keyword">return</xhtml:span>;
        }

        <xhtml:span class="hljs-comment">// We matched a collection; test if we allow the particular request </xhtml:span>
        <xhtml:span class="hljs-comment">// method</xhtml:span>
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!in_array($method, <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;allowedCollectionMethods)) {
            $response-&gt;setStatusCode(<xhtml:span class="hljs-number">405</xhtml:span>);
            <xhtml:span class="hljs-keyword">return</xhtml:span> $response;
        }
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Note that I moved the allowed methods into properties; if I did
the above, I'd refactor the <xhtml:code>options()</xhtml:code> method to use
those properties as well to ensure they are kept in sync.</xhtml:p>
<xhtml:p>Also note that in the case of an invalid method, I return a
response object. This ensures that nothing else needs to execute in
the controller; I discover the problem and return early.</xhtml:p>
<xhtml:h2>End-User Documentation</xhtml:h2>
<xhtml:p>Now that we have the technical solution out of the way, we're
still left with the bulk of the work left to accomplish: providing
end-user documentation detailing the various payloads, errors,
etc.</xhtml:p>
<xhtml:p>I've seen two compelling approaches to this problem. The first
builds on the <xhtml:code>OPTIONS</xhtml:code> method, and the other uses a
hypermedia link in every response to point to documentation.</xhtml:p>
<xhtml:p>The <xhtml:code>OPTIONS</xhtml:code> solution is this: <xhtml:a href="http://zacstewart.com/2012/04/14/http-options-method.html">use the
body of an <xhtml:code>OPTIONS</xhtml:code> response to provide
documentation</xhtml:a>. (Keith Casey <xhtml:a href="https://vimeo.com/49613738">gave an excellent short presentation
about this at REST Fest 2012</xhtml:a>).</xhtml:p>
<xhtml:p>The <xhtml:code>OPTIONS</xhtml:code> method allows for you to return a body
in the response, and also allows for content negotiation. The
theory, then, is that you return media-type-specific documentation
that details the methods allowed, and what they specifically accept
in the body. While there is no standard for this at this time, the
first article I linked suggested including a description, the
parameters expected, and one or more example request bodies for
each HTTP method allowed; you'd likely also want to detail the
responses that can be expected.</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"POST"</xhtml:span>: {
        <xhtml:span class="hljs-string">"description"</xhtml:span>: <xhtml:span class="hljs-string">"Create a new status"</xhtml:span>,
        <xhtml:span class="hljs-string">"parameters"</xhtml:span>: {
            <xhtml:span class="hljs-string">"type"</xhtml:span>: {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"string"</xhtml:span>,
                <xhtml:span class="hljs-string">"description"</xhtml:span>: <xhtml:span class="hljs-string">"Status type -- text, image, or url; defaults to text"</xhtml:span>,
                <xhtml:span class="hljs-string">"required"</xhtml:span>: <xhtml:span class="hljs-literal">false</xhtml:span>
            },
            <xhtml:span class="hljs-string">"text"</xhtml:span>: {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"string"</xhtml:span>,
                <xhtml:span class="hljs-string">"description"</xhtml:span>: <xhtml:span class="hljs-string">"Status text; required for text types, optional for others"</xhtml:span>,
                <xhtml:span class="hljs-string">"required"</xhtml:span>: <xhtml:span class="hljs-literal">false</xhtml:span>
            },
            <xhtml:span class="hljs-string">"image_url"</xhtml:span>: {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"string"</xhtml:span>,
                <xhtml:span class="hljs-string">"description"</xhtml:span>: <xhtml:span class="hljs-string">"URL of image for image types; required for image types"</xhtml:span>,
                <xhtml:span class="hljs-string">"required"</xhtml:span>: <xhtml:span class="hljs-literal">false</xhtml:span>
            },
            <xhtml:span class="hljs-string">"link_url"</xhtml:span>: {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"string"</xhtml:span>,
                <xhtml:span class="hljs-string">"description"</xhtml:span>: <xhtml:span class="hljs-string">"URL of image for link types; required for link types"</xhtml:span>,
                <xhtml:span class="hljs-string">"required"</xhtml:span>: <xhtml:span class="hljs-literal">false</xhtml:span>
            }
        },
        <xhtml:span class="hljs-string">"responses"</xhtml:span>: [
            {
                <xhtml:span class="hljs-string">"describedBy"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/problems/invalid-status"</xhtml:span>,
                <xhtml:span class="hljs-string">"title"</xhtml:span>: <xhtml:span class="hljs-string">"Submitted status was invalid"</xhtml:span>,
                <xhtml:span class="hljs-string">"detail"</xhtml:span>: <xhtml:span class="hljs-string">"Missing text field required for text type"</xhtml:span>
            },
            {
                <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"abcdef123456"</xhtml:span>,
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"text"</xhtml:span>,
                <xhtml:span class="hljs-string">"text"</xhtml:span>: <xhtml:span class="hljs-string">"This is a status update"</xhtml:span>,
                <xhtml:span class="hljs-string">"timestamp"</xhtml:span>: <xhtml:span class="hljs-string">"2013-02-22T10:06:05+0:00"</xhtml:span>
            }
        ],
        <xhtml:span class="hljs-string">"examples"</xhtml:span>: [
            {
                <xhtml:span class="hljs-string">"text"</xhtml:span>: <xhtml:span class="hljs-string">"This is a status update"</xhtml:span>
            },
            {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"image"</xhtml:span>,
                <xhtml:span class="hljs-string">"text"</xhtml:span>: <xhtml:span class="hljs-string">"This is the image caption"</xhtml:span>,
                <xhtml:span class="hljs-string">"image_url"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/favicon.ico"</xhtml:span>
            },
            {
                <xhtml:span class="hljs-string">"type"</xhtml:span>: <xhtml:span class="hljs-string">"link"</xhtml:span>,
                <xhtml:span class="hljs-string">"text"</xhtml:span>: <xhtml:span class="hljs-string">"This is a description of the link"</xhtml:span>,
                <xhtml:span class="hljs-string">"link_url"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/"</xhtml:span>
            },
        ]
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>If you were to use this methodology, you would alter the
<xhtml:code>options()</xhtml:code> method such that it does not return a
response object, but instead return a view model with the
documentation.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">namespace</xhtml:span> <xhtml:span class="hljs-title">My</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">FooController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $viewModelMap = <xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-comment">/* ... */</xhtml:span>);

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">options</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $response = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getResponse();
        $headers  = $response-&gt;getHeaders();

        <xhtml:span class="hljs-comment">// Get a view model based on Accept types</xhtml:span>
        $model    = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;acceptableViewModelSelector(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;viewModelMap);

        <xhtml:span class="hljs-comment">// If you want to vary based on whether this is a collection or an</xhtml:span>
        <xhtml:span class="hljs-comment">// individual item in that collection, check if an identifier from</xhtml:span>
        <xhtml:span class="hljs-comment">// the route is present</xhtml:span>
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;params()-&gt;fromRoute(<xhtml:span class="hljs-string">'id'</xhtml:span>, <xhtml:span class="hljs-keyword">false</xhtml:span>)) {
            <xhtml:span class="hljs-comment">// Still set the Allow header</xhtml:span>
            $headers-&gt;addHeaderLine(<xhtml:span class="hljs-string">'Allow'</xhtml:span>, implode(
                <xhtml:span class="hljs-string">','</xhtml:span>, 
                <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;allowedResourceMethods
            ));

            <xhtml:span class="hljs-comment">// Set documentation specification as variables</xhtml:span>
            $model-&gt;setVariables(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getResourceDocumentationSpec());
            <xhtml:span class="hljs-keyword">return</xhtml:span> $model;
        }

        <xhtml:span class="hljs-comment">// Allow only retrieval and creation on collections</xhtml:span>
        $headers-&gt;addHeaderLine(<xhtml:span class="hljs-string">'Allow'</xhtml:span>, implode(
            <xhtml:span class="hljs-string">','</xhtml:span>,
            <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;allowedCollectionMethods
        ));
        $model-&gt;setVariables(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getCollectionDocumentationSpec());
        <xhtml:span class="hljs-keyword">return</xhtml:span> $model;
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>I purposely didn't provide the implementations of the
<xhtml:code>getResourceDocumentationSpec()</xhtml:code> and
<xhtml:code>getCollectionDocumentationSpec()</xhtml:code> methods, as that will
likely be highly specific to your application. Another possibility
is to use your view engine for this, and specify a template file
that has the fully-populated information. This would require a
custom renderer when using JSON or XML, but is a pretty easy
solution.</xhtml:p>
<xhtml:p><xhtml:strong>However, there's one cautionary tale to tell</xhtml:strong>,
something I already mentioned: <xhtml:code>OPTIONS</xhtml:code>, per the
specification, is <xhtml:em>non-cacheable</xhtml:em>. What this means is that
everytime somebody makes an <xhtml:code>OPTIONS</xhtml:code> request, any cache
control headers you provide will be ignored, which means hitting
the server for each and every request to the documentation.
Considering documentation is static, this is problematic; it has
even prompted <xhtml:a href="http://www.mnot.net/blog/2012/10/29/NO_OPTIONS">blog posts urging
you not to use OPTIONS for documentation</xhtml:a>.</xhtml:p>
<xhtml:p>Which brings us to the second solution for end-user
documentation: a static page referenced via a hypermedia link.</xhtml:p>
<xhtml:p>This solution is insanely easy: you simply provide a
<xhtml:code>Link</xhtml:code> header in your response, and provide a
<xhtml:code>describedby</xhtml:code> reference pointing to the documentation
page:</xhtml:p>
<xhtml:pre><xhtml:code class="language-http hljs http" data-lang="http"><xhtml:span class="hljs-attribute">Link</xhtml:span>: &lt;http://example.com/api/documentation.md&gt;; rel="describedby"
</xhtml:code></xhtml:pre>
<xhtml:p>With ZF2, this is trivially easy to accomplish: create a route
and endpoint for your documentation, and then a listener on your
controller that adds the <xhtml:code>Link</xhtml:code> header to your
response.</xhtml:p>
<xhtml:p>The latter, adding the link header, might look like this:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">namespace</xhtml:span> <xhtml:span class="hljs-title">My</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">EventManager</xhtml:span>\<xhtml:span class="hljs-title">EventManagerInterface</xhtml:span>;
<xhtml:span class="hljs-keyword">use</xhtml:span> <xhtml:span class="hljs-title">Zend</xhtml:span>\<xhtml:span class="hljs-title">Mvc</xhtml:span>\<xhtml:span class="hljs-title">Controller</xhtml:span>\<xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>;

<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">FooController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">AbstractRestfulController</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">setEventManager</xhtml:span><xhtml:span class="hljs-params">(EventManagerInterface $events)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">parent</xhtml:span>::setEventManager($events);
        $events-&gt;attach(<xhtml:span class="hljs-string">'dispatch'</xhtml:span>, <xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-keyword">$this</xhtml:span>, <xhtml:span class="hljs-string">'injectLinkHeader'</xhtml:span>), <xhtml:span class="hljs-number">20</xhtml:span>);
    }

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">injectLinkHeader</xhtml:span><xhtml:span class="hljs-params">($e)</xhtml:span>
    </xhtml:span>{
        $response = $e-&gt;getResponse();
        $headers  = $response-&gt;getHeaders();
        $headers-&gt;addHeaderLine(<xhtml:span class="hljs-string">'Link'</xhtml:span>, sprintf(
            <xhtml:span class="hljs-string">'&lt;%s&gt;; rel="describedby"'</xhtml:span>, 
            <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;url(<xhtml:span class="hljs-string">'documentation-route-name'</xhtml:span>)
        ));
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>If you want to ensure you get a fully qualified URL that
includes the schema, hostname, and port, there are a number of ways
to do that as well; the above gives you the basic idea.</xhtml:p>
<xhtml:p>Now, for the route and endpoint, there are tools that will help
you simplify that task as well, in the form of a couple of ZF2
modules: <xhtml:a href="https://github.com/weierophinney/PhlySimplePage">PhlySimplePage</xhtml:a>
and <xhtml:a href="https://github.com/Soflomo/Prototype">Soflomo\Prototype</xhtml:a>.
<xhtml:em>(Disclosure: I'm the author of PhlySimplePage.)</xhtml:em></xhtml:p>
<xhtml:p>Both essentially allow you to specify a route and the
corresponding template name to use, which means all you need to do
is provide a little configuration, and a view template.
<xhtml:code>Soflomo\Prototype</xhtml:code> has slightly simpler configuration,
so I'll demonstrate it here:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'soflomo_prototype'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'documentation-route-name'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'route'</xhtml:span>    =&gt; <xhtml:span class="hljs-string">'/api/documentation'</xhtml:span>,
            <xhtml:span class="hljs-string">'template'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'api/documentation'</xhtml:span>,
        ),
    ),
    <xhtml:span class="hljs-string">'view_manager'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'template_map'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(
            <xhtml:span class="hljs-string">'api/documentation'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">__DIR__</xhtml:span> . <xhtml:span class="hljs-string">'/../view/api/documentation.phtml'</xhtml:span>,
        ),
    ),
);
</xhtml:code></xhtml:pre>
<xhtml:p>I personally have been using the <xhtml:code>Link</xhtml:code> header
solution, as it's so simple to implement. It does <xhtml:em>not</xhtml:em>
write the documentation for you, but thinking about it early and
implementing it helps ensure you at least start writing the
documentation, and, if you open source your project, you may find
you have users who will write the documentation for you if they
know where it lives.</xhtml:p>
<xhtml:h2>Conclusions</xhtml:h2>
<xhtml:p>Document your API, or either nobody will use it, or all you're
hear are complaints from your users about having to guess
constantly about how to use it. Include the following
information:</xhtml:p>
<xhtml:ul>
<xhtml:li>What endpoint(s) is (are) available.</xhtml:li>
<xhtml:li>Which operations are available for each endpoint.
<xhtml:ul>
<xhtml:li>What payloads are expected by the endpoint.</xhtml:li>
<xhtml:li>What payloads can a user expect in return.</xhtml:li>
<xhtml:li>What media types may be used for requests.</xhtml:li>
<xhtml:li>What media types may be expected in responses.</xhtml:li>
</xhtml:ul>
</xhtml:li>
</xhtml:ul>
<xhtml:p>Additionally, make sure that you do the
<xhtml:code>OPTIONS</xhtml:code>/<xhtml:code>Allow</xhtml:code> dance; don't just accept
any request method, and report the standard 405 response for
methods that you will not allow. Make sure you differentiate these
for collections versus individual resources, as you likely may
allow replacing or updating an individual resource, but likely will
not want to do the same for a whole collection!</xhtml:p>
<xhtml:h2>Next time</xhtml:h2>
<xhtml:p>So far, I've covered the basics of RESTful JSON APIS,
specifically recommending Hypermedia Application Language (HAL) for
providing hypermedia linking and relations. I've covered error
reporting, and provided two potential formats (API-Problem and
vnd.error) for use with your APIs. Now, in this article, I've shown
a bit about documenting your API both for machine consumption as
well as end-users. What's left?</xhtml:p>
<xhtml:p>In upcoming parts, I'll talk about ZF2's
<xhtml:code>AbstractRestfulController</xhtml:code> in more detail, as well as
how to perform some basic content negotiation. I've also had
requests about how one might deal with API versioning, and will
attempt to demonstrate some techniques for doing that as well.
Finally, expect to see a post showing how I've tied all of this
together in a general-purpose ZF2 module so that you can ignore all
of these posts and simply start writing APIs.</xhtml:p>
<xhtml:h3>Updates</xhtml:h3>
<xhtml:p><xhtml:em>Note: I'll update this post with links to the other posts in
the series as I publish them.</xhtml:em></xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="/blog/2013-02-11-restful-apis-with-zf2-part-1.html">Part
1</xhtml:a></xhtml:li>
<xhtml:li><xhtml:a href="/blog/2013-02-13-restful-apis-with-zf2-part-2.html">Part
2</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2013-02-25-restful-apis-with-zf2-part-3.html">
RESTful APIs with ZF2, Part 3</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2013-02-25T06:29:00-06:00">25
February 2013</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[RESTful APIs with ZF2, Part 2]]></title>
    <published>2013-02-13T07:40:00-06:00</published>
    <updated>2013-02-13T07:40:00-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2013-02-13-restful-apis-with-zf2-part-2.html"/>
    <id>https://mwop.net/blog/2013-02-13-restful-apis-with-zf2-part-2.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>In my <xhtml:a href="/blog/2013-02-11-restful-apis-with-zf2-part-1.html">last post</xhtml:a>,
I covered some background on REST and the Richardson Maturity
Model, and some emerging standards around hypermedia APIs in JSON;
in particular, I outlined aspects of Hypermedia Application
Language (HAL), and how it can be used to define a generic
structure for JSON resources.</xhtml:p>
<xhtml:p>In this post, I cover an aspect of RESTful APIs that's often
overlooked: reporting problems.</xhtml:p>
<xhtml:h2>Background</xhtml:h2>
<xhtml:p>APIs are useful when they're working. But when they fail,
they're only useful if they provide us with meaningful information;
if all I get is a status code, and no indication of what caused the
issue, or where I might look for more information, I get
frustrated.</xhtml:p>
<xhtml:p>In consuming APIs, I've come to the following conclusions:</xhtml:p>
<xhtml:ul>
<xhtml:li>Error conditions need to provide detailed information as to
what went wrong, and what steps I may be able to take next. An
error code with no context gives me nothing to go on.</xhtml:li>
<xhtml:li>Errors need to be reported consistently. Don't report the error
one way one time, and another way the next.</xhtml:li>
<xhtml:li><xhtml:strong>DO</xhtml:strong> use HTTP status codes to indicate an error
happened. Nothing is more irksome than getting back a 200 status
with an error payload.</xhtml:li>
<xhtml:li>Errors should be reported in a format I have indicated I will
Accept (as in the HTTP header). Perhaps the only think more irksome
than a 200 status code for an error is getting back an HTML page
when I expect JSON.</xhtml:li>
</xhtml:ul>
<xhtml:h2>Why Status Codes Aren't Enough</xhtml:h2>
<xhtml:p>Since REST leverages and builds on HTTP, an expedient solution
for reporting problems is to simply use <xhtml:a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP
status codes</xhtml:a>. These are well understood by web developers,
right?</xhtml:p>
<xhtml:p><xhtml:code>4xx</xhtml:code> error codes are errors made by the requestor,
and are actually fairly reasonable to use for reporting things such
as lack of authorization tokens, incomplete requests, unsupportable
operations, or non-supported media types.</xhtml:p>
<xhtml:p>But what happens when the error is on the server — because
something has gone wrong such as inability to reach your
persistence layer or credential storage? The <xhtml:code>5xx</xhtml:code>
series of status codes is sparse and wholly unsuited to reporting
errors of these types — <xhtml:em>though you'll likely still want to use
a <xhtml:code>500</xhtml:code> status to report the failure</xhtml:em>. But what do
you present to the consumer so that they know whether or not to try
again, or what to report to you so that you can fix the issue?</xhtml:p>
<xhtml:p>A status code simply isn't enough information most of the time.
Yes, you want to define standard status codes so that your clients
can perform reasonable branching, but you also need a way to
communicate <xhtml:em>details</xhtml:em> to the end-user, so that they can log
the information for themselves, display information to their own
end-users, and/or report it back to you so you can do something to
resolve the situation.</xhtml:p>
<xhtml:h2>Custom Media Types</xhtml:h2>
<xhtml:p>The first step is to use a custom media type. Media types are
typically both a name as well as a structure — and the latter is
what we're after when it comes to error reporting.</xhtml:p>
<xhtml:p>If we return a response using this media type, the client then
knows how to parse it, and can then process it, log it,
whatever.</xhtml:p>
<xhtml:p>Sure, you can make up your own format — as long as you are
consistent in using it, and you document it. But personally, I
don't like inventing new formats when standard formats exist
already. Custom formats mean that custom clients are required for
working with the services; using a standard format can save effort
and time.</xhtml:p>
<xhtml:p>In the world of JSON, I've come across two error media types
that appear to be gaining traction:
<xhtml:code>application/api-problem+json</xhtml:code> and
<xhtml:code>application/vnd.error+json</xhtml:code></xhtml:p>
<xhtml:h3>API-Problem</xhtml:h3>
<xhtml:p>This particular media type is <xhtml:a href="http://tools.ietf.org/html/draft-nottingham-http-problem-02">via
the IETF</xhtml:a>. Like HAL, it provides formats in both JSON and XML,
making it a nice cross-platform choice.</xhtml:p>
<xhtml:p>As noted already, the media type is
<xhtml:code>application/api-problem+json</xhtml:code>. The representation is a
single resource, with the following properties:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:strong>describedBy</xhtml:strong>: a URL to a document describing
the error condition (required)</xhtml:li>
<xhtml:li><xhtml:strong>title</xhtml:strong>: a brief title for the error condition
(required)</xhtml:li>
<xhtml:li><xhtml:strong>httpStatus</xhtml:strong>: the HTTP status code for the
current request (optional)</xhtml:li>
<xhtml:li><xhtml:strong>detail</xhtml:strong>: error details specific to this request
(optional)</xhtml:li>
<xhtml:li><xhtml:strong>supportId</xhtml:strong>: a URL to the specific problem
occurrence (e.g., to a log message) (optional)</xhtml:li>
</xhtml:ul>
<xhtml:p>As an example:</xhtml:p>
<xhtml:pre><xhtml:code class="language-http hljs http" data-lang="http">HTTP/1.1 <xhtml:span class="hljs-number">500</xhtml:span> Internal Error
<xhtml:span class="hljs-attribute">Content-Type</xhtml:span>: application/api-problem+json

{
    "describedBy": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html",
    "detail": "Status failed validation",
    "httpStatus": 500,
    "title": "Internal Server Error"
}
</xhtml:code></xhtml:pre>
<xhtml:p>The specification allows a large amount of flexibility — you can
have your own custom error types, so long as you have a description
of them to link to. You can provide as little or as much detail as
you want, and even decide what information to expose based on
environment.</xhtml:p>
<xhtml:p>I personally like to point to the HTTP status code definitions,
and then provide request-specific detail; I find this gives quick
and simple results that I can later shape as I add more detail to
my API. However, the specification definitely encourages you to
have unique error types with discrete URIs that describe them —
never a bad thing when creating APIs.</xhtml:p>
<xhtml:h3>vnd.error</xhtml:h3>
<xhtml:p>This is a <xhtml:a href="https://github.com/blongden/vnd.error">proposed media type</xhtml:a>
within the HAL community. Like HAL, it provides formats in both
JSON and XML, making it a nice cross-platform choice.</xhtml:p>
<xhtml:p>It differentiates from API-Problem in a few ways. First, it
allows, and even encourages, reporting collections of errors. If
you consider PHP exceptions and the fact that they support
"previous" exceptions, this is a powerful concept; you can report
the entire chain of errors that led to the response. Second, it
encourages pushing detail out of the web service; errors include a
"logRef" property that points to where the error detail lives. This
is probably better illustrated than explained.</xhtml:p>
<xhtml:p>The response payload is an array of objects. Each object has the
following members:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:strong>logRef</xhtml:strong>: a unique identifier for the specific
error which can then be used to identify the error within
server-side logs (required)</xhtml:li>
<xhtml:li><xhtml:strong>message</xhtml:strong>: the error message itself
(required)</xhtml:li>
<xhtml:li><xhtml:strong>_links</xhtml:strong>: HAL-compatible links. Typically,
"help", "describes", and/or "describedBy" relations will be defined
here.</xhtml:li>
</xhtml:ul>
<xhtml:p>As an example, let's consider the API-Problem example I had
earlier, and provide a <xhtml:code>vnd.error</xhtml:code> equivalent:</xhtml:p>
<xhtml:pre><xhtml:code class="language-http hljs http" data-lang="http">HTTP/1.1 <xhtml:span class="hljs-number">500</xhtml:span> Internal Error
<xhtml:span class="hljs-attribute">Content-Type</xhtml:span>: application/vnd.error+json

[
    {
        "logRef": "someSha1HashMostLikely",
        "message": "Status failed validation",
        "_links": {
            "describedBy": {"href": "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html"}
        }
    }
]
</xhtml:code></xhtml:pre>
<xhtml:p><xhtml:code>vnd.error</xhtml:code> basically begs you to create custom error
types, with documentation end-points that detail the source of the
error and what you can do about it (this is true of API-Problem as
well).</xhtml:p>
<xhtml:p>The requirement to include a log reference ("logRef") and have
it be unique can be a stumbling block to implementation, however,
as it requires effort for uniquely identifying requests, and
logging. However, both the identification and logging can be
automated.</xhtml:p>
<xhtml:h2>Summary</xhtml:h2>
<xhtml:p>Error reporting in APIs is as important as the normal resource
payloads themselves. Without good error reporting, when an API
raises errors, clients have difficulty understanding what they can
do next, and cannot provide you, the API provider, with information
that will allow you to debug on the server side.</xhtml:p>
<xhtml:p>As noted at the beginning of the article, if you follow the
rules below, you'll make consumers of your API happier and more
productive.</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:strong>DO</xhtml:strong> use appropriate HTTP status codes to
indicate an error happened.</xhtml:li>
<xhtml:li>Report errors in a format I have indicated I will Accept (as in
the HTTP header).</xhtml:li>
<xhtml:li>Report errors consistently. Don't report the error one way one
time, and another way the next. Standardize on a specific
error-reporting media type . While you <xhtml:em>can</xhtml:em> create your own
error structure, I recommend using documented, accepted standards.
This will make clients more re-usable, and make many of your
decisions for you.</xhtml:li>
<xhtml:li>Provide detailed information as to what went wrong, and what
steps I may be able to take next. Provide documentation for each
type of error, and link to that documentation from your error
payloads.</xhtml:li>
</xhtml:ul>
<xhtml:p>Which brings me to…</xhtml:p>
<xhtml:h2>Next time</xhtml:h2>
<xhtml:p>I realize I still haven't covered anything specific to ZF2, but
I'll start next time, when I cover the next topic: documenting your
API. An undocumented API is a useless API, so it's good to start
baking documentation in immediately. I'll survey some of the
possibilities and how they can be implemented in ZF2 in the next
installment, and then we can get our hands dirty with actual API
development.</xhtml:p>
<xhtml:h3>Updates</xhtml:h3>
<xhtml:p><xhtml:em>Note: I'll update this post with links to the other posts in
the series as I publish them.</xhtml:em></xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="/blog/2013-02-11-restful-apis-with-zf2-part-1.html">Part
1</xhtml:a></xhtml:li>
<xhtml:li><xhtml:a href="/blog/2013-02-25-restful-apis-with-zf2-part-3.html">Part
3</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2013-02-13-restful-apis-with-zf2-part-2.html">
RESTful APIs with ZF2, Part 2</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2013-02-13T07:40:00-06:00">13
February 2013</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[RESTful APIs with ZF2, Part 1]]></title>
    <published>2013-02-12T05:42:00-06:00</published>
    <updated>2013-02-13T07:40:00-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/2013-02-11-restful-apis-with-zf2-part-1.html"/>
    <id>https://mwop.net/blog/2013-02-11-restful-apis-with-zf2-part-1.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>RESTful APIs have been an interest of mine for a couple of
years, but due to <xhtml:a href="http://framework.zend.com/blog//zend-framework-2-0-0-stable-released.html">
circumstances</xhtml:a>, I've not had much chance to work with them in
any meaningful fashion until recently.</xhtml:p>
<xhtml:p><xhtml:a href="http://akrabat.com/">Rob Allen</xhtml:a> and I proposed a
workshop for <xhtml:a href="http://conference.phpbenelux.eu/2013/">PHP
Benelux 2013</xhtml:a> covering RESTful APIs with ZF2. When it was
accepted, it gave me the perfect opportunity to dive in and start
putting the various pieces together.</xhtml:p>
<xhtml:h2>Background</xhtml:h2>
<xhtml:p>I've attended any number of conference sessions on API design,
read countless articles, and engaged in quite a number of
conversations. Three facts keep cropping up:</xhtml:p>
<xhtml:ol>
<xhtml:li>JSON is fast becoming the preferred exchange format due to the
ease with which it de/serializes in almost every language.</xhtml:li>
<xhtml:li>The "holy grail" is <xhtml:a href="http://martinfowler.com/articles/richardsonMaturityModel.html">Richardson
Maturity Model</xhtml:a> Level 3.</xhtml:li>
<xhtml:li>It's really hard to achieve RMM level 3 with JSON.</xhtml:li>
</xhtml:ol>
<xhtml:h3>Richardson Maturity Model</xhtml:h3>
<xhtml:p>As a quick review, the Richardson Maturity Model has the
following 4 levels:</xhtml:p>
<xhtml:ul>
<xhtml:li>Level 0: "The swamp of POX." Basically, a service that uses TCP
for transport, primarily as a form of remote procedure call (RPC).
Typically, these are not really leveraging HTTP in any meaningful
fashion; most systems will use HTTP POST for all interactions.
Also, you will often have a single endpoint for all interactions,
regardless of whether or not they are strictly related. XML-RPC,
SOAP, and JSON-RPC fall under this category.</xhtml:li>
<xhtml:li>Level 1: "Resources." In these services, you start breaking the
service into multiple services, one per "resource," or, in object
oriented terms, per object. This means a distinct URL per object,
which means each has its own distinct identity on the web; this
often extends not only to the collection of objects, but to
individual objects under the collection as well (e.g.,
<xhtml:code>/books</xhtml:code> as well as <xhtml:code>/books/life-of-pi</xhtml:code>). The
service may still be RPC in nature, however, and, at this level,
often is still using a single HTTP method for all interactions with
the resource.</xhtml:li>
<xhtml:li>Level 2: "HTTP Verbs." At this level, we start using HTTP verbs
with our services in the way the HTTP specification intends. GET is
for safe operations, and should be cacheable; POST is used for
creation and/or updating; DELETE can be used to delete a resource;
etc. Rather than doing RPC style methods, we leverage HTTP,
occasionally passing additional parameters via the query string or
request body. Considerations such as HTTP caching and idempotence
are taken into account.</xhtml:li>
<xhtml:li>Level 3: "Hypermedia Controls." Building on the previous level,
our resource representations now also include <xhtml:em>links</xhtml:em>, which
indicate what we can <xhtml:em>do next</xhtml:em>. At this level, our API
becomes practically self-describing; given a single end-point, we
should be able to start crawling it, using the links in a
representation to lead us to the next actions.</xhtml:li>
</xhtml:ul>
<xhtml:p>When I first started playing with web services around a decade
ago, everything was stuck at Level 0 or Level 1 — usually with
Level 1 users downgrading to Level 0 because Level 0 offerred
consistency and predictability if you chose to use a service type
that had a defined envelope format (such as XML-RPC or SOAP). (I
even wrote the XML-RPC server implementation for Zend Framework
because I got sick of writing one-off parsers/serializers for
custom XML web service implementations. When you're implementing
many services, predictability is a huge win.)</xhtml:p>
<xhtml:p>A few years ago, I started seeing a trend towards Level 2. Web
developers like the simplicity of using HTTP verbs, as they map
very well to <xhtml:a href="http://en.wikipedia.org/wiki/Create,_read,_update_and_delete">CRUD</xhtml:a>
operations — the bread and butter of web development. Couple this
concept with JSON, and it becomes trivially simple to both create a
web service, as well as consume it.</xhtml:p>
<xhtml:p><xhtml:em>I'd argue that the majority of web developers are quite
happy to be at Level 2 — and have no problem staying there. They're
productive, and the concepts are easy — both to understand and to
implement.</xhtml:em></xhtml:p>
<xhtml:p>Level 3, though, is where it becomes really interesting. The
idea that I can examine the represention <xhtml:em>alone</xhtml:em> in order to
understand what I can do next is very intriguing and
empowering.</xhtml:p>
<xhtml:h3>JSON and Hypermedia</xhtml:h3>
<xhtml:p>With XML, hypermedia basically comes for free. Add some
<xhtml:code>&lt;link&gt;</xhtml:code> elements to your representation, and
you're done — and don't forget the link <xhtml:code>rel</xhtml:code>ations!</xhtml:p>
<xhtml:p>JSON, however, is another story.</xhtml:p>
<xhtml:p>Where do the links go? <xhtml:em>There is no single, defined way to
represent a hyperlink in JSON.</xhtml:em></xhtml:p>
<xhtml:p>Fortunately, there are some emerging standards.</xhtml:p>
<xhtml:p>First is use of the <xhtml:a href="http://www.w3.org/wiki/LinkHeader">"Link" HTTP header</xhtml:a>. While
the page I linked shows only a single link in the header, you can
have multiple links separated by commas. GitHub uses this when
providing pagination links in their API. Critics will point out
that the HTTP headers are not technically part of the
representation, however; strict interpetations of REST and RMM
indicate that the hypermedia links should be part of the resource
representation. Regardless, having the links in the HTTP headers is
useful for pre-traversal of a service, as you can perform HEAD
requests only to discover possible actions and workflows.</xhtml:p>
<xhtml:p><xhtml:a href="http://amundsen.com/media-types/collection/format/">Collection+JSON</xhtml:a>
is interesting, as it describes the entire JSON envelope. My one
criticism is that it details too much; whenever I see a format that
dictates how to describe types, I think of XML-RPC or SOAP, and get
a little twitchy. It's definitely worth a look, though.</xhtml:p>
<xhtml:p>What's captured my attention of late, however, is <xhtml:a href="http://stateless.co/hal_specification.html">Hypertext Application
Language</xhtml:a>, or HAL for short. HAL has very few rules, but
succinctly describes both how to provide hypermedia in JSON as well
as how to represent embedded resources — the two things that most
need standardized structure in JSON. It does this while still
providing a generic media type, and also describing a mirror image
XML format!</xhtml:p>
<xhtml:h3>HAL Media Types</xhtml:h3>
<xhtml:p>HAL defines two generic media types:
<xhtml:code>application/hal+xml</xhtml:code> and
<xhtml:code>application/hal+json</xhtml:code>. You will use these as the
response <xhtml:code>Content-Type</xhtml:code>, as they describe the response
representation; the client can simply request
<xhtml:code>application/json</xhtml:code>, and the response format remains
compatible.</xhtml:p>
<xhtml:h3>HAL and Links</xhtml:h3>
<xhtml:p>HAL provides a very simple structure for JSON hypermedia links.
First, all resource representations must contain hypermedia links,
and all links are provided in a <xhtml:code>_links</xhtml:code> object:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Second, links are properties of this object. The property name
is the link relation, and the value is an object containing
minimally an "href" property.</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1234"</xhtml:span>}
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>If a given relation can have multiple links, you provide instead
an array of objects:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1234"</xhtml:span>},
        <xhtml:span class="hljs-string">"conversation"</xhtml:span>: [
            {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1237"</xhtml:span>},
            {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1241"</xhtml:span>}
        ]
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Individual links can contain other attributes as desired — I've
seen people include the relation again so that it's self-contained
in the link object, and it's not uncommon to include a title or
name.</xhtml:p>
<xhtml:h3>HAL and Resources</xhtml:h3>
<xhtml:p>HAL imposes no structure over resources other than requiring the
hypermedia links; even then, you typically do not include the
hypermedia links when making a request of the web service; the
hypermedia links are included only in the representations
<xhtml:em>returned</xhtml:em> by the service.</xhtml:p>
<xhtml:p>So, as an example, you would POST the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-http hljs http" data-lang="http"><xhtml:span class="hljs-attribute">POST /api/status
Host</xhtml:span>: example.com
<xhtml:span class="hljs-attribute">Accept</xhtml:span>: application/json
<xhtml:span class="hljs-attribute">Content-Type</xhtml:span>: application/json

{
    "status": "This is my awesome status update!",
    "user": "mwop"
}
</xhtml:code></xhtml:pre>
<xhtml:p>And from that request, you'd receive the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-http hljs http" data-lang="http"><xhtml:span class="hljs-attribute">201 Created
Location</xhtml:span>: http://example.com/api/status/1347
<xhtml:span class="hljs-attribute">Content-Type</xhtml:span>: application/hal+json

{
    "_links": {
        "self": {"href": "http://example.com/api/status/1347"}
    },
    "id": "1347",
    "timestamp": "2013-02-11 23:33:47",
    "status": "This is my awesome status update!",
    "user": "mwop"
}
</xhtml:code></xhtml:pre>
<xhtml:h3>HAL and Embedded Resources</xhtml:h3>
<xhtml:p>The other important thing that HAL defines is how to
<xhtml:em>embed</xhtml:em> resources. Why is this important? If the resource
references other resources, you will want to be able to link to
them so you can perform operations on them, too.</xhtml:p>
<xhtml:p>Embedded resources are represented inside an
<xhtml:code>_embedded</xhtml:code> object of the representation, and, as
resources, contain their own <xhtml:code>_links</xhtml:code> object as well.
Each resource you embed is assigned to a property of that object,
and if multiple objects of the same type are returned, an array of
resources is assigned. In fact, this latter is how you represent
<xhtml:em>collections</xhtml:em> in HAL.</xhtml:p>
<xhtml:p>Let's consider a simple example first. In previous code samples,
I have a "user" that's a string; let's make that an embedded
resource instead.</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1347"</xhtml:span>}
    },
    <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"1347"</xhtml:span>,
    <xhtml:span class="hljs-string">"timestamp"</xhtml:span>: <xhtml:span class="hljs-string">"2013-02-11 23:33:47"</xhtml:span>,
    <xhtml:span class="hljs-string">"status"</xhtml:span>: <xhtml:span class="hljs-string">"This is my awesome status update!"</xhtml:span>,
    <xhtml:span class="hljs-string">"_embedded"</xhtml:span>: {
        <xhtml:span class="hljs-string">"user"</xhtml:span>: {
            <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/user/mwop"</xhtml:span>}
            }
            <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"mwop"</xhtml:span>,
            <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"Matthew Weier O'Phinney"</xhtml:span>,
            <xhtml:span class="hljs-string">"url"</xhtml:span>: <xhtml:span class="hljs-string">"http://mwop.net"</xhtml:span>
        }
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>I've moved the "user" out of the representation, and into the
<xhtml:code>_embedded</xhtml:code> object — because this is where you define
embedded resources. Note that the "user" is a standard HAL resource
itself — containing hypermedia links.</xhtml:p>
<xhtml:p>Now let's look at a collection:</xhtml:p>
<xhtml:pre><xhtml:code class="language-javascript hljs javascript" data-lang="javascript">{
    <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
        <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status"</xhtml:span>},
        <xhtml:span class="hljs-string">"next"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status?page=2"</xhtml:span>},
        <xhtml:span class="hljs-string">"last"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status?page=100"</xhtml:span>}
    },
    <xhtml:span class="hljs-string">"count"</xhtml:span>: <xhtml:span class="hljs-number">2973</xhtml:span>,
    <xhtml:span class="hljs-string">"per_page"</xhtml:span>: <xhtml:span class="hljs-number">30</xhtml:span>,
    <xhtml:span class="hljs-string">"page"</xhtml:span>: <xhtml:span class="hljs-number">1</xhtml:span>,
    <xhtml:span class="hljs-string">"_embedded"</xhtml:span>: {
        <xhtml:span class="hljs-string">"status"</xhtml:span>: [
            {
                <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                    <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/status/1347"</xhtml:span>}
                },
                <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"1347"</xhtml:span>,
                <xhtml:span class="hljs-string">"timestamp"</xhtml:span>: <xhtml:span class="hljs-string">"2013-02-11 23:33:47"</xhtml:span>,
                <xhtml:span class="hljs-string">"status"</xhtml:span>: <xhtml:span class="hljs-string">"This is my awesome status update!"</xhtml:span>,
                <xhtml:span class="hljs-string">"_embedded"</xhtml:span>: {
                    <xhtml:span class="hljs-string">"user"</xhtml:span>: {
                        <xhtml:span class="hljs-string">"_links"</xhtml:span>: {
                            <xhtml:span class="hljs-string">"self"</xhtml:span>: {<xhtml:span class="hljs-string">"href"</xhtml:span>: <xhtml:span class="hljs-string">"http://example.com/api/user/mwop"</xhtml:span>}
                        }
                        <xhtml:span class="hljs-string">"id"</xhtml:span>: <xhtml:span class="hljs-string">"mwop"</xhtml:span>,
                        <xhtml:span class="hljs-string">"name"</xhtml:span>: <xhtml:span class="hljs-string">"Matthew Weier O'Phinney"</xhtml:span>,
                        <xhtml:span class="hljs-string">"url"</xhtml:span>: <xhtml:span class="hljs-string">"http://mwop.net"</xhtml:span>
                    }
                }
            }
            <xhtml:span class="hljs-comment">/* ... */</xhtml:span>
        ]
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Note that the "status" property is an array; semantically, all
resources under this key are of the same type. Also note that the
parent resource has some additional link relations — these are
related to pagination, and allow a client to determine what the
next and last pages are (and, if we were midway into the
collection, previous and first pages). Since the collection is also
a resource, it has some interesting metadata — how many resources
are in the collection, how many we represent per page, and what the
current page is.</xhtml:p>
<xhtml:p>Also note that you can nest resources — simply include an
<xhtml:code>_embedded</xhtml:code> object inside an embedded resource, with
additional resources, as I've done with the "user" resource inside
the status resource shown here. It's turtles all the way down.</xhtml:p>
<xhtml:h2>Next Time</xhtml:h2>
<xhtml:p>The title of this post indicates I'll be talking about building
RESTful APIs with ZF2 — but so far, I've not said anything about
ZF2.</xhtml:p>
<xhtml:p>I'll get there. But there's another detour to take: reporting
errors.</xhtml:p>
<xhtml:h3>Updates</xhtml:h3>
<xhtml:p><xhtml:em>Note: I'll update this post with links to the other posts in
the series as I publish them.</xhtml:em></xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:a href="/blog/2013-02-13-restful-apis-with-zf2-part-2.html">Part
2</xhtml:a></xhtml:li>
<xhtml:li><xhtml:a href="/blog/2013-02-25-restful-apis-with-zf2-part-3.html">Part
3</xhtml:a></xhtml:li>
</xhtml:ul>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/2013-02-11-restful-apis-with-zf2-part-1.html">
RESTful APIs with ZF2, Part 1</xhtml:a> was originally published
<xhtml:time class="dt-published" datetime="2013-02-12T05:42:00-06:00">12
February 2013</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Responding to Different Content Types in RESTful ZF Apps]]></title>
    <published>2010-03-04T15:28:07-06:00</published>
    <updated>2010-03-10T09:28:22-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/233-Responding-to-Different-Content-Types-in-RESTful-ZF-Apps.html"/>
    <id>https://mwop.net/blog/233-Responding-to-Different-Content-Types-in-RESTful-ZF-Apps.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>In <xhtml:a href="/blog/227-Exposing-Service-APIs-via-Zend-Framework.html">previous</xhtml:a>
<xhtml:a href="/blog/228-Building-RESTful-Services-with-Zend-Framework.html">articles</xhtml:a>,
I've explored building service endpoints and RESTful services with
Zend Framework. With RPC-style services, you get to cheat: the
protocol dictates the content type (XML-RPC uses XML, JSON-RPC uses
JSON, SOAP uses XML, etc.). With REST, however, you have to make
choices: what serialization format will you support?</xhtml:p>
<xhtml:p>Why not support multiple formats?</xhtml:p>
<xhtml:p>There's no reason you can't re-use your RESTful web service to
support multiple formats. Zend Framework and PHP have plenty of
tools to assist you in responding to different format requests, so
don't limit yourself. With a small amount of work, you can make
your controllers format agnostic, and ensure that you respond
appropriately to different requests.</xhtml:p>
<xhtml:h2>Content-Type Detection</xhtml:h2>
<xhtml:p>The first problem to solve is going to be how to retrieve passed
parameters. When using XML or JSON as your serialization format,
you aren't getting your standard POST variables — you're getting a
raw post instead, and you'll need to deserialize the payload. In
fact, if you're getting a PUT request, you also have some work to
do, as PHP doesn't do anything with PUT requests.</xhtml:p>
<xhtml:p>I do this via an action helper. The basic algorithm is:</xhtml:p>
<xhtml:ul>
<xhtml:li>Do we have a raw body in the request? If not, nothing more need
be done.</xhtml:li>
<xhtml:li>Determine the Content-Type passed in the request headers, and
decode appropriately:
<xhtml:ul>
<xhtml:li>If it was JSON, pass the raw request body to
<xhtml:code>json_decode</xhtml:code> or <xhtml:code>Zend_Json::decode</xhtml:code>.</xhtml:li>
<xhtml:li>If it was XML, I pass the raw request body to the
<xhtml:code>Zend_Config_XML</xhtml:code> constructor, and then serialize to an
arrya using the <xhtml:code>toArray()</xhtml:code> method. Yes, it's a hack,
but it's effective.</xhtml:li>
<xhtml:li>Otherwise, I assume I've got a regular PUT-style request, and I
pass the data to <xhtml:code>parse_str()</xhtml:code>.</xhtml:li>
</xhtml:ul>
</xhtml:li>
</xhtml:ul>
<xhtml:p>I keep the values within the action helper, and then retrieve
them on demand within my action controller. The helper looks like
the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Scrummer_Controller_Helper_Params</xhtml:span> 
    <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Controller_Action_Helper_Abstract</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-comment">/**
     * <xhtml:span class="hljs-doctag">@var</xhtml:span> array Parameters detected in raw content body
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $_bodyParams = <xhtml:span class="hljs-keyword">array</xhtml:span>();

    <xhtml:span class="hljs-comment">/**
     * Do detection of content type, and retrieve parameters from raw body if 
     * present
     * 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> void
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">init</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $request     = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getRequest();
        $contentType = $request-&gt;getHeader(<xhtml:span class="hljs-string">'Content-Type'</xhtml:span>);
        $rawBody     = $request-&gt;getRawBody();
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!$rawBody) {
            <xhtml:span class="hljs-keyword">return</xhtml:span>;
        }
        <xhtml:span class="hljs-keyword">switch</xhtml:span> (<xhtml:span class="hljs-keyword">true</xhtml:span>) {
            <xhtml:span class="hljs-keyword">case</xhtml:span> (strstr($contentType, <xhtml:span class="hljs-string">'application/json'</xhtml:span>)):
                <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;setBodyParams(Zend_Json::decode($rawBody));
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
            <xhtml:span class="hljs-keyword">case</xhtml:span> (strstr($contentType, <xhtml:span class="hljs-string">'application/xml'</xhtml:span>)):
                $config = <xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Config_Xml($rawBody);
                <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;setBodyParams($config-&gt;toArray());
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
            <xhtml:span class="hljs-keyword">default</xhtml:span>:
                <xhtml:span class="hljs-keyword">if</xhtml:span> ($request-&gt;isPut()) {
                    parse_str($rawBody, $params);
                    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;setBodyParams($params);
                }
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
        }
    }

    <xhtml:span class="hljs-comment">/**
     * Set body params
     * 
     * <xhtml:span class="hljs-doctag">@param</xhtml:span>  array $params 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> Scrummer_Controller_Action
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">setBodyParams</xhtml:span><xhtml:span class="hljs-params">(array $params)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_bodyParams = $params;
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>;
    }

    <xhtml:span class="hljs-comment">/**
     * Retrieve body parameters
     * 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> array
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">getBodyParams</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_bodyParams;
    }

    <xhtml:span class="hljs-comment">/**
     * Get body parameter
     * 
     * <xhtml:span class="hljs-doctag">@param</xhtml:span>  string $name 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> mixed
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">getBodyParam</xhtml:span><xhtml:span class="hljs-params">($name)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;hasBodyParam($name)) {
            <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_bodyParams[$name];
        }
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">null</xhtml:span>;
    }

    <xhtml:span class="hljs-comment">/**
     * Is the given body parameter set?
     * 
     * <xhtml:span class="hljs-doctag">@param</xhtml:span>  string $name 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> bool
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">hasBodyParam</xhtml:span><xhtml:span class="hljs-params">($name)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">isset</xhtml:span>(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_bodyParams[$name])) {
            <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">true</xhtml:span>;
        }
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">false</xhtml:span>;
    }

    <xhtml:span class="hljs-comment">/**
     * Do we have any body parameters?
     * 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> bool
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">hasBodyParams</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!<xhtml:span class="hljs-keyword">empty</xhtml:span>(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_bodyParams)) {
            <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">true</xhtml:span>;
        }
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">false</xhtml:span>;
    }

    <xhtml:span class="hljs-comment">/**
     * Get submit parameters
     * 
     * <xhtml:span class="hljs-doctag">@return</xhtml:span> array
     */</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">getSubmitParams</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;hasBodyParams()) {
            <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getBodyParams();
        }
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getRequest()-&gt;getPost();
    }

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">direct</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">return</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getSubmitParams();
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>This helper is intended to be run on each request, so I register
it in my bootstrap:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Bootstrap</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Application_Bootstrap_Bootstrap</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-comment">// ...</xhtml:span>
    <xhtml:span class="hljs-keyword">protected</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">_initActionHelpers</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-comment">// ...</xhtml:span>
        $params = <xhtml:span class="hljs-keyword">new</xhtml:span> Scrummer_Controller_Helper_Params();
        Zend_Controller_Action_HelperBroker::addHelper($params);
        <xhtml:span class="hljs-comment">// ...</xhtml:span>
    }
    <xhtml:span class="hljs-comment">// ...</xhtml:span>
}
</xhtml:code></xhtml:pre>
<xhtml:p>Within your action controller, all you need to do is call the
helper:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$data = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;params();
</xhtml:code></xhtml:pre>
<xhtml:p>In a RESTful controller, you'll only need to use this with your
<xhtml:code>postAction</xhtml:code> and <xhtml:code>putAction</xhtml:code>. The beauty is
that your controller can remain ignorant of the Content-Type — you
write the same logic to retrieve your parameters regardless.</xhtml:p>
<xhtml:h2>Responding to the client: Context Switching</xhtml:h2>
<xhtml:p>So, the first half of the problem is taken care of: how to
handle the request. The second half is responding
appropriately.</xhtml:p>
<xhtml:p>Zend Framework has some built in tooling to help with this. The
ContextSwitch and AjaxContext action helpers look for a particular
parameter — "format" by default — and, if detected, will render an
alternate view script named after the context. As an example, if an
"XML" context is detected, it will render
<xhtml:code>&lt;controller&gt;/&lt;action&gt;.xml.phtml</xhtml:code> — note the
<xhtml:code>.xml</xhtml:code> segment of the script name.</xhtml:p>
<xhtml:p>Both helpers work in the same basic way (the latter,
AjaxContext, will only activate if the request is determined to
originate from an XMLHttpRequest): you define which actions in the
controller are context sensitive, and then if the context is
detected, a new view script will be used.</xhtml:p>
<xhtml:p>So, the first trick is ensuring that the context is passed. As
mentioned before, the helpers look for a "format" parameter in the
request object. You can pass this using a query parameter —
<xhtml:code>?format=xml</xhtml:code> — but I find that ugly. There's an HTTP
header defined for this purpose already: "Accept".</xhtml:p>
<xhtml:p>Detecting the header and injecting the context into the request
is absurdly simple, and can be done in a
<xhtml:code>dispatchLoopStartup</xhtml:code> plugin:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Scrummer_Controller_Plugin_AcceptHandler</xhtml:span>
    <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Controller_Plugin_Abstract</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">dispatchLoopStartup</xhtml:span><xhtml:span class="hljs-params">(Zend_Controller_Request_Abstract $request)</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!$request <xhtml:span class="hljs-keyword">instanceof</xhtml:span> Zend_Controller_Request_Http) {
            <xhtml:span class="hljs-keyword">return</xhtml:span>;
        }

        $header = $request-&gt;getHeader(<xhtml:span class="hljs-string">'Accept'</xhtml:span>);
        <xhtml:span class="hljs-keyword">switch</xhtml:span> (<xhtml:span class="hljs-keyword">true</xhtml:span>) {
            <xhtml:span class="hljs-keyword">case</xhtml:span> (strstr($header, <xhtml:span class="hljs-string">'application/json'</xhtml:span>)):
                $request-&gt;setParam(<xhtml:span class="hljs-string">'format'</xhtml:span>, <xhtml:span class="hljs-string">'json'</xhtml:span>);
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
            <xhtml:span class="hljs-keyword">case</xhtml:span> (strstr($header, <xhtml:span class="hljs-string">'application/xml'</xhtml:span>) 
                  &amp;&amp; (!strstr($header, <xhtml:span class="hljs-string">'html'</xhtml:span>))):
                $request-&gt;setParam(<xhtml:span class="hljs-string">'format'</xhtml:span>, <xhtml:span class="hljs-string">'xml'</xhtml:span>);
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
            <xhtml:span class="hljs-keyword">default</xhtml:span>:
                <xhtml:span class="hljs-keyword">break</xhtml:span>;
        }
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>The above can be registered in your application
configuration:</xhtml:p>
<xhtml:pre><xhtml:code class="language-ini hljs ini" data-lang="ini"><xhtml:span class="hljs-attr">resources.frontController.plugins[]</xhtml:span> = <xhtml:span class="hljs-string">"Scrummer_Controller_Plugin_AcceptHandler"</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:p>I like my RESTful controllers to automatically expose their
methods as context-aware. To make this happen, I defined a marker
interface, <xhtml:code>Scrummer_Rest_Controller</xhtml:code>, and created an
action helper that checks if the current controller implements it;
if it does, I then automatically add contexts for the RESTful
actions.</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Scrummer_Controller_Helper_RestContexts</xhtml:span>
    <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Controller_Action_Helper_Abstract</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-keyword">protected</xhtml:span> $_contexts = <xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'xml'</xhtml:span>, 
        <xhtml:span class="hljs-string">'json'</xhtml:span>,
    );

    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">preDispatch</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $controller = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getActionController();
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!$controller <xhtml:span class="hljs-keyword">instanceof</xhtml:span> Scrummer_Rest_Controller) {
            <xhtml:span class="hljs-keyword">return</xhtml:span>;
        }

        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_initContexts();

        <xhtml:span class="hljs-comment">// Set a Vary response header based on the Accept header</xhtml:span>
        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getResponse()-&gt;setHeader(<xhtml:span class="hljs-string">'Vary'</xhtml:span>, <xhtml:span class="hljs-string">'Accept'</xhtml:span>);
    }

    <xhtml:span class="hljs-keyword">protected</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">_initContexts</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $cs = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getActionController()-&gt;contextSwitch;
        $cs-&gt;setAutoJsonSerialization(<xhtml:span class="hljs-keyword">false</xhtml:span>);
        <xhtml:span class="hljs-keyword">foreach</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_contexts <xhtml:span class="hljs-keyword">as</xhtml:span> $context) {
            <xhtml:span class="hljs-keyword">foreach</xhtml:span> (<xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-string">'index'</xhtml:span>, <xhtml:span class="hljs-string">'post'</xhtml:span>, <xhtml:span class="hljs-string">'get'</xhtml:span>, <xhtml:span class="hljs-string">'put'</xhtml:span>, <xhtml:span class="hljs-string">'delete'</xhtml:span>) <xhtml:span class="hljs-keyword">as</xhtml:span> $action) {
                $cs-&gt;addActionContext($action, $context);
            }
        }
        $cs-&gt;initContext();
    }
}
</xhtml:code></xhtml:pre>
<xhtml:p>Register this via the bootstrap as well:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">Bootstrap</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Application_Bootstrap_Bootstrap</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-comment">// ...</xhtml:span>
    <xhtml:span class="hljs-keyword">protected</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">_initActionHelpers</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        <xhtml:span class="hljs-comment">// ...</xhtml:span>
        $params = <xhtml:span class="hljs-keyword">new</xhtml:span> Scrummer_Controller_Helper_Params();
        Zend_Controller_Action_HelperBroker::addHelper($params);

        $contexts = <xhtml:span class="hljs-keyword">new</xhtml:span> Scrummer_Controller_Helper_RestContexts();
        Zend_Controller_Action_HelperBroker::addHelper($contexts);
        <xhtml:span class="hljs-comment">// ...</xhtml:span>
    }
    <xhtml:span class="hljs-comment">// ...</xhtml:span>
}
</xhtml:code></xhtml:pre>
<xhtml:p>There are two things to note about this helper. First, you'll
see that I specify a "Vary" header. This is to ensure that if the
client chooses to cache responses, it will cache separate responses
based on the value sent in the "Accept" header.</xhtml:p>
<xhtml:p>Second, note that I turn off automatic JSON serialization in the
ContextSwitch helper. I do this so that I can keep my controller
context agnostic; this will require additional view scripts, but
the ability to keep my controller logic simple will be worth it.
More on that in a moment.</xhtml:p>
<xhtml:p>We now have the infrastructure in place to respond to different
contexts based on the "Accept" header, and can retrieve parameters
appropriately based on the "Content-Type" provided us. Now comes
the actual response.</xhtml:p>
<xhtml:h2>Responding to the client: Views</xhtml:h2>
<xhtml:p>Recall that ContextSwitch will attach an additional prefix to
the specified view script —
<xhtml:code>&lt;controller&gt;/&lt;action&gt;.phtml</xhtml:code> will become
<xhtml:code>&lt;controller&gt;/&lt;action&gt;.xml.phtml</xhtml:code> or
<xhtml:code>&lt;controller&gt;/&lt;action&gt;.json.phtml</xhtml:code>.
Basically, for each context we will respond to, we have an
additional view script per action.</xhtml:p>
<xhtml:pre><xhtml:code class="language-lua hljs lua" data-lang="lua">views/
|<xhtml:span class="hljs-comment">-- scripts/</xhtml:span>
|   `<xhtml:span class="hljs-comment">-- foo/</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- delete.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- delete.json.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- delete.xml.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- get.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- get.json.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- get.xml.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- index.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- index.json.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- index.xml.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- post.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- post.json.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- post.xml.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- put.phtml</xhtml:span>
|      |<xhtml:span class="hljs-comment">-- put.json.phtml</xhtml:span>
|      `<xhtml:span class="hljs-comment">-- put.xml.phtml</xhtml:span>
</xhtml:code></xhtml:pre>
<xhtml:p>This may seem like overkill, but consider the following
representative method from my controller:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">postAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span>
    </xhtml:span>{
        $data    = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;params();
        $service = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;getService();
        $result  = $service-&gt;add($data);  
        <xhtml:span class="hljs-keyword">if</xhtml:span> (!$result) {
            <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;view-&gt;form = $service-&gt;getBacklogForm();
            <xhtml:span class="hljs-keyword">return</xhtml:span>;
        }

        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;view-&gt;success = <xhtml:span class="hljs-keyword">true</xhtml:span>;
        <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;view-&gt;backlog = $result;
    }
</xhtml:code></xhtml:pre>
<xhtml:p>You don't see anything in there about headers, redirects, or XHR
requests. Just slinging data to services and views. Real
simple.</xhtml:p>
<xhtml:p>The view scripts then take care of the appropriate display
logic. Let's look at two view scripts for the above action, one for
plain old HTML, the other for a JSON response:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-meta">&lt;?php</xhtml:span> <xhtml:span class="hljs-comment">// backlog/post.phtml <xhtml:span class="hljs-meta">?&gt;</xhtml:span></xhtml:span>
<xhtml:span class="hljs-meta">&lt;?php</xhtml:span> 
<xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;success):
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;response-&gt;setRedirect(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;url(<xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'controller'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'backlog'</xhtml:span>,
        <xhtml:span class="hljs-string">'id'</xhtml:span>         =&gt; <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;backlog-&gt;id,
    ), <xhtml:span class="hljs-string">'rest'</xhtml:span>, <xhtml:span class="hljs-keyword">true</xhtml:span>));
<xhtml:span class="hljs-keyword">else</xhtml:span>: <xhtml:span class="hljs-meta">?&gt;</xhtml:span>
&lt;h2&gt;Create <xhtml:span class="hljs-keyword">new</xhtml:span> backlog&lt;/h2&gt;
<xhtml:span class="hljs-meta">&lt;?php</xhtml:span>
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;form-&gt;setAction(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;url())
               -&gt;setMethod(<xhtml:span class="hljs-string">'post'</xhtml:span>);
    <xhtml:span class="hljs-keyword">echo</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;form;
<xhtml:span class="hljs-keyword">endif</xhtml:span> <xhtml:span class="hljs-meta">?&gt;</xhtml:span>

<xhtml:span class="hljs-meta">&lt;?php</xhtml:span> <xhtml:span class="hljs-comment">// backlog/post.json.phtml <xhtml:span class="hljs-meta">?&gt;</xhtml:span></xhtml:span>
<xhtml:span class="hljs-meta">&lt;?php</xhtml:span>
<xhtml:span class="hljs-keyword">if</xhtml:span> (<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;success) {
    $url = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;url(<xhtml:span class="hljs-keyword">array</xhtml:span>(
        <xhtml:span class="hljs-string">'controller'</xhtml:span> =&gt; <xhtml:span class="hljs-string">'backlog'</xhtml:span>,
        <xhtml:span class="hljs-string">'id'</xhtml:span>         =&gt; <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;backlog-&gt;id,
    ), <xhtml:span class="hljs-string">'rest'</xhtml:span>, <xhtml:span class="hljs-keyword">true</xhtml:span>);
    <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;response-&gt;setHeader(<xhtml:span class="hljs-string">'Location'</xhtml:span>, $url)
                   -&gt;setHttpResponseCode(<xhtml:span class="hljs-number">201</xhtml:span>);
    <xhtml:span class="hljs-keyword">echo</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;json(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;backlog-&gt;toArray());
    <xhtml:span class="hljs-keyword">return</xhtml:span>;
}

$form = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;form;
$form-&gt;setAction(<xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;url())
     -&gt;setMethod(<xhtml:span class="hljs-string">'post'</xhtml:span>);
<xhtml:span class="hljs-keyword">echo</xhtml:span> <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;jsonFormErrors($form);
</xhtml:code></xhtml:pre>
<xhtml:p>A few things to note: I inject my response object into the view.
I feel HTTP headers are part of the view, and thus I deal with them
there. That also serves the purpose of keeping my controllers thin
and agnostic. Additionally, you'll note that I use different
response codes for HTML versus JSON — this allows my JSON-REST
support to be RESTful, by returning a 201 status code indicating
the resource was created; I also return a JSON representation of
the object. Finally, you'll note that I have a special view helper
for creating JSON representations of validation errors.</xhtml:p>
<xhtml:h2>Closing points</xhtml:h2>
<xhtml:p>This post is far from exhaustive, and I expect it will likely
raise at least as many questions as it tries to answer.</xhtml:p>
<xhtml:p>My main point in this article is to get you, the reader and
developer, thinking creatively about how to expose RESTful web
services. Hopefully, you're taking the following away:</xhtml:p>
<xhtml:ol>
<xhtml:li>Architect in such a way as to minimize the code in your
controllers; keep that code as agnostic as possible in regards to
where input comes from and what type of response is required.</xhtml:li>
<xhtml:li>Use front controller plugins and action helpers to create
scaffolding for your services; these are incredibly flexible and
re-usable, and help make point 1 that much easier.</xhtml:li>
<xhtml:li>Offload as much as possible to your views. This will allow you
to isolate logic specific to given formats.</xhtml:li>
</xhtml:ol>
<xhtml:p>What are you waiting for? Don't you have an API to expose?</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/233-Responding-to-Different-Content-Types-in-RESTful-ZF-Apps.html">
Responding to Different Content Types in RESTful ZF Apps</xhtml:a> was
originally published <xhtml:time class="dt-published" datetime="2010-03-04T15:28:07-06:00">4 March 2010</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
  <entry xmlns:xhtml="http://www.w3.org/1999/xhtml">
    <title type="html"><![CDATA[Building RESTful Services with Zend Framework]]></title>
    <published>2009-11-09T09:00:00-06:00</published>
    <updated>2009-11-11T10:38:41-06:00</updated>
    <link rel="alternate" type="text/html" href="https://mwop.net/blog/228-Building-RESTful-Services-with-Zend-Framework.html"/>
    <id>https://mwop.net/blog/228-Building-RESTful-Services-with-Zend-Framework.html</id>
    <author>
      <name>Matthew Weier O'Phinney</name>
      <email>contact@mwop.net</email>
      <uri>https://mwop.net</uri>
    </author>
    <content xmlns:xhtml="http://www.w3.org/1999/xhtml" type="xhtml">
      <xhtml:div xmlns:xhtml="http://www.w3.org/1999/xhtml"><xhtml:p>As a followup to my <xhtml:a href="/blog/227-Exposing-Service-APIs-via-Zend-Framework.html">previous
post</xhtml:a>, I now turn to RESTful web services. I originally
encountered the term when attending php|tropics in 2005, where
<xhtml:a href="http://twitter.com/g_schlossnagle">George
Schlossnaggle</xhtml:a> likened it to simple GET and POST requests. Since
then, the architectural style — and developer understanding of the
architectural style — has improved a bit, and a more solid
definition can be made.</xhtml:p>
<xhtml:p>At its heart, <xhtml:a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">REST</xhtml:a>
simply dictates that a given resource have a unique address, and
that you interact with that resource using HTTP verbs. The standard
verbs utilized are:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:em>GET</xhtml:em>: retrieve a list of resources, or, if an
identifier is present, view a single resource</xhtml:li>
<xhtml:li><xhtml:em>POST</xhtml:em>: create a new resource with the data provided in
the POST</xhtml:li>
<xhtml:li><xhtml:em>PUT</xhtml:em>: update an existing resource as specified by an
identifier, using the PUT data</xhtml:li>
<xhtml:li><xhtml:em>DELETE</xhtml:em>: delete an existing resource as specified by an
identifier</xhtml:li>
</xhtml:ul>
<xhtml:p>The standard URL structure used is as follows:</xhtml:p>
<xhtml:ul>
<xhtml:li><xhtml:code>/resource</xhtml:code> - GET (list) and POST operations</xhtml:li>
<xhtml:li><xhtml:code>/resource/{identifier}</xhtml:code> - GET (view), PUT, and
DELETE operations</xhtml:li>
</xhtml:ul>
<xhtml:p>What the REST paradigm provides you is a simple, standard way to
structure your CRUD (Create-Read-Update-Delete) applications. Due
to the large number of REST clients available, it also means that
if you follow the rules, you get a ton of interoperability with
those clients.</xhtml:p>
<xhtml:p>As of <xhtml:a href="http://framework.zend.com/">Zend Framework</xhtml:a>
1.9.0, it's trivially easy to create RESTful routes for your MVC
application, as well as to handle the various REST actions via
action controllers.</xhtml:p>
<xhtml:p><xhtml:a href="http://framework.zend.com/manual/en/zend.controller.router.html#zend.controller.router.routes.rest">
Zend_Rest_Route</xhtml:a> allows you to define RESTful controllers at
several levels:</xhtml:p>
<xhtml:ul>
<xhtml:li>You can make it the default route, meaning that unless you have
additional routes, all controllers will be considered REST
controllers.</xhtml:li>
<xhtml:li>You can specify modules that contain RESTful controllers.</xhtml:li>
<xhtml:li>You can specify specific controllers per module that are
RESTful</xhtml:li>
</xhtml:ul>
<xhtml:p>As examples:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php">$front = Zend_Controller_Front::getInstance();
$router = $front-&gt;getRouter();

<xhtml:span class="hljs-comment">// Specifying all controllers as RESTful:</xhtml:span>
$restRoute = <xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Rest_Route($front);
$router-&gt;addRoute(<xhtml:span class="hljs-string">'default'</xhtml:span>, $restRoute);

<xhtml:span class="hljs-comment">// Specifying the "api" module only as RESTful:</xhtml:span>
$restRoute = <xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Rest_Route($front, <xhtml:span class="hljs-keyword">array</xhtml:span>(), <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'api'</xhtml:span>,
));
$router-&gt;addRoute(<xhtml:span class="hljs-string">'rest'</xhtml:span>, $restRoute);

<xhtml:span class="hljs-comment">// Specifying the "api" module as RESTful, and the "task" controller of the</xhtml:span>
<xhtml:span class="hljs-comment">// "backlog" module as RESTful:</xhtml:span>
$restRoute = <xhtml:span class="hljs-keyword">new</xhtml:span> Zend_Rest_Route($front, <xhtml:span class="hljs-keyword">array</xhtml:span>(), <xhtml:span class="hljs-keyword">array</xhtml:span>(
    <xhtml:span class="hljs-string">'api'</xhtml:span>,
    <xhtml:span class="hljs-string">'backlog'</xhtml:span> =&gt; <xhtml:span class="hljs-keyword">array</xhtml:span>(<xhtml:span class="hljs-string">'task'</xhtml:span>),
));
$router-&gt;addRoute(<xhtml:span class="hljs-string">'rest'</xhtml:span>, $restRoute);
</xhtml:code></xhtml:pre>
<xhtml:p>To define a RESTful action controller, you can either extend
<xhtml:code>Zend_Rest_Controller</xhtml:code>, or simply define the following
methods in a standard controller extending
<xhtml:code>Zend_Controller_Action</xhtml:code> (you'll need to define them
regardless):</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-comment">// Or extend Zend_Rest_Controller</xhtml:span>
<xhtml:span class="hljs-class"><xhtml:span class="hljs-keyword">class</xhtml:span> <xhtml:span class="hljs-title">RestController</xhtml:span> <xhtml:span class="hljs-keyword">extends</xhtml:span> <xhtml:span class="hljs-title">Zend_Controller_Action</xhtml:span>
</xhtml:span>{
    <xhtml:span class="hljs-comment">// Handle GET and return a list of resources</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">indexAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{}

    <xhtml:span class="hljs-comment">// Handle GET and return a specific resource item</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">getAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{}

    <xhtml:span class="hljs-comment">// Handle POST requests to create a new resource item</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">postAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{}

    <xhtml:span class="hljs-comment">// Handle PUT requests to update a specific resource item</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">putAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{}

    <xhtml:span class="hljs-comment">// Handle DELETE requests to delete a specific item</xhtml:span>
    <xhtml:span class="hljs-keyword">public</xhtml:span> <xhtml:span class="hljs-function"><xhtml:span class="hljs-keyword">function</xhtml:span> <xhtml:span class="hljs-title">deleteAction</xhtml:span><xhtml:span class="hljs-params">()</xhtml:span> </xhtml:span>{}
}
</xhtml:code></xhtml:pre>
<xhtml:p>For those methods that operate on individual resources
(<xhtml:code>getAction()</xhtml:code>, <xhtml:code>putAction()</xhtml:code>, and
<xhtml:code>deleteAction()</xhtml:code>), you can test for the identifier using
the following:</xhtml:p>
<xhtml:pre><xhtml:code class="language-php hljs php" data-lang="php"><xhtml:span class="hljs-keyword">if</xhtml:span> (!$id = <xhtml:span class="hljs-keyword">$this</xhtml:span>-&gt;_getParam(<xhtml:span class="hljs-string">'id'</xhtml:span>, <xhtml:span class="hljs-keyword">false</xhtml:span>)) {
    <xhtml:span class="hljs-comment">// report error, redirect, etc.</xhtml:span>
}
</xhtml:code></xhtml:pre>
<xhtml:h2>Responding is an art</xhtml:h2>
<xhtml:p>Many developers are either unaware of or ignore the part of the
specification that dictates what the <xhtml:em>response</xhtml:em> should look
like.</xhtml:p>
<xhtml:p>For instance, in classic REST, after performing a POST to create
a new item, you should do the following:</xhtml:p>
<xhtml:ul>
<xhtml:li>Set the HTTP response code to 201, indicating "Created"</xhtml:li>
<xhtml:li>Set the Location header to point to the canonical URI for the
newly created item: <xhtml:code>/team/31</xhtml:code></xhtml:li>
<xhtml:li>Provide a representation of the newly created item</xhtml:li>
</xhtml:ul>
<xhtml:p>Note that there's no redirect, which flies in the face of
standard web development (where GET-POST-Redirect is the typical
format). This is a common "gotcha" moment.</xhtml:p>
<xhtml:p>Similarly, with PUT requests, you simply indicate an HTTP 200
status when successful, and show a representation of the updated
item. DELETE requests should return an HTTP 204 status (indicating
success - no content), with no body content.</xhtml:p>
<xhtml:p><xhtml:em>Note: when building RESTful HTML applications, you may want
to still do GET-POST-Redirect to prevent caching issues. The above
applies to RESTful web services, which typically use XML or JSON
for transactions, and have smart clients for interacting with the
service.</xhtml:em></xhtml:p>
<xhtml:p>I'll be writing another article soon showing some tips and
tricks for interacting with HTTP headers, both from the request and
for the response, as it's a subject lengthy enough for a post of
its own. In the meantime, start playing with
<xhtml:code>Zend_Rest_Route</xhtml:code> and standardizing on it for your CRUD
operations!</xhtml:p>
<xhtml:div class="h-entry"><xhtml:img class="u-photo photo" width="50" src="https://avatars0.githubusercontent.com/u/25943?v=3&amp;u=79dd2ea1d4d8855944715d09ee4c86215027fa80&amp;s=140" alt="matthew"/> <xhtml:a class="u-url u-uid p-name" href="https://mwop.net/blog/228-Building-RESTful-Services-with-Zend-Framework.html">
Building RESTful Services with Zend Framework</xhtml:a> was originally
published <xhtml:time class="dt-published" datetime="2009-11-09T09:00:00-06:00">9 November 2009</xhtml:time> on <xhtml:a href="https://mwop.net">https://mwop.net</xhtml:a> by <xhtml:a rel="author" class="p-author" href="https://mwop.net">Matthew Weier
O'Phinney</xhtml:a>.</xhtml:div>
</xhtml:div>
    </content>
  </entry>
</feed>
