<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matt Moore</title>
    <description>The latest articles on DEV Community by Matt Moore (@mattnmoore).</description>
    <link>https://dev.to/mattnmoore</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F98166%2F275dd6b9-ba12-425f-8805-53a2a8931c03.jpeg</url>
      <title>DEV Community: Matt Moore</title>
      <link>https://dev.to/mattnmoore</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mattnmoore"/>
    <language>en</language>
    <item>
      <title>Abstracting Laravel Dependencies</title>
      <dc:creator>Matt Moore</dc:creator>
      <pubDate>Mon, 16 Dec 2019 15:56:45 +0000</pubDate>
      <link>https://dev.to/mattnmoore/abstracting-laravel-dependencies-17nn</link>
      <guid>https://dev.to/mattnmoore/abstracting-laravel-dependencies-17nn</guid>
      <description>&lt;p&gt;Over the course of building a Laravel application, most developers utilize numerous composer packages to implement common functionality. It's important to think about future-proofing these 3rd-party dependencies or you may find yourself battling considerable technical debt in the future. &lt;br&gt;
One way to do this is to apply the DRY principle to your dependencies. Keep them in one place, so that if you ever need to change, upgrade, or replace a 3rd-party package, you can do it with minimal headache. I'll explore a couple strategies for doing this in the rest of the article. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This is by no means exclusively applicable to Laravel or even PHP, but I'll be focusing on Laravel for examples and specific scenarios for this article. &lt;/p&gt;
&lt;h2&gt;
  
  
  #1: Create an Interface and a Wrapper Implementation
&lt;/h2&gt;

&lt;p&gt;I was once working on a codebase that used Guzzle in several places in the application. When Guzzle released a breaking upgrade, it was a lot of extra work hunting down all the places it was called to make the upgrade. &lt;/p&gt;

&lt;p&gt;To prevent us from having to spend the same amount of time if the scenario came up again (it did, and always will), I first created a &lt;code&gt;HttpClient&lt;/code&gt; interface that described all the functionality we wanted to use from the new version of Guzzle. Then, I created a &lt;code&gt;GuzzleWrapper&lt;/code&gt; class that wraps Guzzle's Client class and adheres to the interface. &lt;/p&gt;

&lt;p&gt;Once I added a binding in Laravel's IoC container, I replaced every place that Guzzle was called with the new Interface instead. This ensures that the next time I had to do an upgrade, I only had to do it in that one class. &lt;/p&gt;

&lt;p&gt;One day, a new Http package might come out that performs better, or has better security, or shiny new features. All I would have to do is create a new implementation using that new package, swap out the binding, and it is good to go.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example: Guzzle
&lt;/h3&gt;

&lt;p&gt;Here is a real-world example of how you could create a wrapper for the popular Http package &lt;a href="http://docs.guzzlephp.org/en/stable/"&gt;Guzzle&lt;/a&gt;. Since Guzzle uses &lt;a href="https://www.php-fig.org/psr/psr-7/"&gt;PSR-7&lt;/a&gt;, we can use the &lt;code&gt;ResponseInterface&lt;/code&gt; included in the &lt;a href="https://github.com/php-fig/http-message"&gt;psr/http-message&lt;/a&gt; package. The wrapper implementation is incomplete, but demonstrates the concepts that can be used to create a wrapper for a 3rd-party package.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Examples are written with features that are new in PHP 7.4 such as class property type declarations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; 

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Core\Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; 

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Core\Http&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Psr\Http\Message\ResponseInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GuzzleWrapper&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;HttpClient&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;Client&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Client&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt; &lt;span class="kt"&gt;ResponseInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uri&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can add the interface and concrete implementation to a &lt;code&gt;$bindings&lt;/code&gt; property in one of your app's service providers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; 

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Core\Providers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Core\Http\GuzzleWrapper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Core\Http\HttpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\ServiceProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CoreServiceProvider&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;ServiceProvider&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$bindings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;HttpClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;GuzzleWrapper&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can resolve the class out of the service container anywhere you need it! Just make sure to inject the &lt;code&gt;HttpClient&lt;/code&gt; interface, and not the &lt;code&gt;GuzzleWrapper&lt;/code&gt; class directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt; 

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Feature&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Core\Http\HttpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiIntegration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;HttpClient&lt;/span&gt; &lt;span class="nv"&gt;$httpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;HttpClient&lt;/span&gt; &lt;span class="nv"&gt;$httpClient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;httpClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$httpClient&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cp"&gt;?&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should avoice creating &lt;a href="https://www.joelonsoftware.com/2002/11/11/the-law-of-leaky-abstractions/"&gt;Leaky Abstractions&lt;/a&gt; to the best of your ability. In our example, we are returning a typehint of a PSR-7 compliant &lt;code&gt;ResponseInterface&lt;/code&gt; rather than the Guzzle Response implementation that actually gets in the hands of the caller. That way, if you change the wrapped class, as long as they are PSR-7 compliant, nothing will break. If it's not PSR-7 complaint, you can simply write a PSR-7 compliant adapter of whatever it does return. &lt;/p&gt;

&lt;p&gt;If whatever class you are wrapping does not have a PSR standard, you can create your own wrapper class based on current behavior for its return or input classes to prevent your abstractions from leaking. The end-goal is to make sure whatever classes call your wrapper don't know the details of the 3rd-party implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  #2: Create a standalone wrapper class
&lt;/h2&gt;

&lt;p&gt;A quicker and dirtier method would be to create a wrapper class without an interface. Almost identical to the first method, but you instead call your wrapper class as a dependency directly. This makes it harder to test, harder to change, and makes it impossible to run multiple implementations simultaneously, so I would recommend avoiding this method.&lt;/p&gt;

&lt;h2&gt;
  
  
  #3: Confine dependency to one class.
&lt;/h2&gt;

&lt;p&gt;If your application only uses a package in one place, and will for the foreseeable future, you may not need to abstract it. The whole point is easing upgrades or changes, so if it truly will only ever live in one place like a service or job class then you gain little benefit from abstraction. Doing this can definitely be a slippery slope, as you may think it only needs to be in one place, to find that it was needed elsewhere, and you or somewhere else simply injected the 3rd-party class directly elsewhere. To be safe, I would avoid this method as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Write Everything Twice
&lt;/h3&gt;

&lt;p&gt;It's important to protected against premature optimizations. This article shares some good ideas regarding when exactly is a good time to abstract something and apply the DRY principle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/wuz/stop-trying-to-be-so-dry-instead-write-everything-twice-wet-5g33"&gt;https://dev.to/wuz/stop-trying-to-be-so-dry-instead-write-everything-twice-wet-5g33&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Laravel Facades
&lt;/h3&gt;

&lt;p&gt;While Facades are technically okay since they resolve out of the IoC container, I still prefer to inject the dependencies into the constructor. It makes it a bit easier to tell exactly what dependencies a class has, and helps improve testability in certain scenarios.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wrap Laravel Helper Methods
&lt;/h3&gt;

&lt;p&gt;While I don't think it's beneficial to wrap all the Laravel dependencies you use unless you suspect you'll one day migrate out of Laravel, which in some cases might be something worth considering, I would consider wrapping Laravel's helper methods if you plan to use them. When the &lt;code&gt;str*()&lt;/code&gt; methods got deprecated in favor of &lt;code&gt;Str::*()&lt;/code&gt;, I had to spend an hour or two between all my codebases making sure that I swapped all of them out. &lt;/p&gt;

&lt;p&gt;I should have created a wrapper class for them so that I can always rely on only changing them in one place should they ever change again.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Creating abstractions for 3rd-party dependencies is a bit of a time investment to get setup, but it provides a lot of benefits and saves time and headache in the future. As always, thanks for reading, and leave your comments and questions in the section below.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://mattdoescode.com/articles/abstracting-laravel-dependencies-2019-12-14"&gt;Abstracting Laravel Dependencies&lt;/a&gt; appeared first on &lt;a href="https://mattdoescode.com"&gt;Matt Does Code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
    <item>
      <title>6 Laravel Tips</title>
      <dc:creator>Matt Moore</dc:creator>
      <pubDate>Sun, 20 Oct 2019 21:55:03 +0000</pubDate>
      <link>https://dev.to/mattnmoore/6-laravel-tips-4k2i</link>
      <guid>https://dev.to/mattnmoore/6-laravel-tips-4k2i</guid>
      <description>&lt;p&gt;I've put together a small list of tips that I've found useful while working with Laravel.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. onDelete('set null')
&lt;/h2&gt;

&lt;p&gt;You probably know about, and have used &lt;code&gt;onDelete('cascade');&lt;/code&gt; on foreign keys in Laravel migrations, but did you know about &lt;code&gt;'set null'&lt;/code&gt;? This allows you to preserve models when their related model is deleted. An example of this would be if you have comments that have a user, if the user gets deleted, and you want to preserve their comments, you can use &lt;code&gt;onDelete('set null')&lt;/code&gt;. This will set your &lt;code&gt;user_id&lt;/code&gt; column to null automatically if the user gets deleted, and you can handle this in your data presentation layer to show ‘User Deleted’ as the author, or something similar.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;foreign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;references&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;onDelete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'set null'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. dropForeign([]);
&lt;/h2&gt;

&lt;p&gt;For the longest time, I thought you had to use the full key name when rolling back a foreign key constraint in a migration. I was also confused when rolling back multiple foreign keys using array syntax didn't work.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// doesn't work&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropForeign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// works&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropForeign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'posts_user_id_foreign'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// doesn't work&lt;/span&gt;
&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropForeign&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'posts_user_id_foreign'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'posts_type_id_foreign'&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I read the documentation to figure out what was going on, I realized that the array syntax on &lt;code&gt;dropForeign&lt;/code&gt; is for dropping a foreign key using a shorthand column name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$table&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropForeign&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'user_id'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Super handy! But why array syntax? What happens if you put multiple strings in there? I looked at the source code to find out since it wasn't obvious to me from the documentation.&lt;/p&gt;

&lt;p&gt;Here is drop foreign:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
* Indicate that the given foreign key should be dropped.
*
* @param  string|array  $index
* @return \Illuminate\Support\Fluent
*/&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;dropForeign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;dropIndexCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'dropForeign'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'foreign'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply an abstracted call to &lt;code&gt;dropIndexCommand&lt;/code&gt; which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cd"&gt;/**
* Create a new drop index command on the blueprint.
*
* @param  string  $command
* @param  string  $type
* @param  string|array  $index
* @return \Illuminate\Support\Fluent
*/&lt;/span&gt;
&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;dropIndexCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

    &lt;span class="c1"&gt;// If the given "index" is actually an array of columns, the developer means&lt;/span&gt;
    &lt;span class="c1"&gt;// to drop an index merely by specifying the columns involved without the&lt;/span&gt;
    &lt;span class="c1"&gt;// conventional name, so we will build the index name from the columns.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;is_array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createIndexName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$columns&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;indexCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$columns&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$index&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, when we call &lt;code&gt;dropForeign&lt;/code&gt; with an array, it builds an index name using the involved columns. So if we had a composite key index, we could drop it using the array syntax and simply pass in the column names, rather than passing in the entire index name just like we do with the foreign key constraint.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Model Validation
&lt;/h2&gt;

&lt;p&gt;There are lots of different ways to perform user input validation in Laravel. You can use Request objects, middleware, or even validate right in your controllers. Recently, I've been defining validation rules in Eloquent Models. You can then hook into those rules wherever you need to, like in a Request object. This approach was inspried by the Elixir framework, Phoenix.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Fillable attributes.
     *
     * @var array
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'user_id'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Validation rules for creation
     *
     * @var array
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$createRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'phone_number'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'integer'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Http\Requests&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Contact&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Foundation\Http\FormRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CreateContact&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;FormRequest&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$createRules&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use multiple rulesets if create and update validation differs. For instance, if your front-end only sends values that have changes for updating, you don't want all fields marked as required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Contact&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Model&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Fillable attributes.
     *
     * @var array
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$fillable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'phone_number'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'user_id'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Validation rules for creation
     *
     * @var array
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$createRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'required|string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'phone_number'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'integer'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Validation rules for update
     *
     * @var array
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nv"&gt;$updateRules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'phone_number'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'string'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s1"&gt;'user_id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'integer'&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Data Migrations
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to put static information in the database for reference throughout your application. Permissions, country or state names, default settings, the list goes on an on. If the data needs to be able to change or needs to be versioned, you can use migrations instead of seeders. I've tried two approaches and they both work well.&lt;/p&gt;

&lt;p&gt;Approach #1 is to simply run queries inserting, updating, or deleting data in a migration. In this scenario I'm backfilling a new setting with a default value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Reports\Utilities\ReportEmailDefaults&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Team\Team&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Settings\Setting&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Schema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Schema\Blueprint&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Migrations\Migration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FillEmailsSetting&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * Run the migrations.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// get all teams&lt;/span&gt;
        &lt;span class="nv"&gt;$teams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Team&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$teams&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// add new default emails setting for each team&lt;/span&gt;
            &lt;span class="nv"&gt;$setting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Setting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nv"&gt;$setting&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'emails'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// get values from constants to avoid magic strings&lt;/span&gt;
            &lt;span class="nv"&gt;$values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'report_subject'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ReportEmailDefaults&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SUBJECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'report_body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;ReportEmailDefaults&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;BODY&lt;/span&gt;
            &lt;span class="p"&gt;];&lt;/span&gt;

            &lt;span class="nv"&gt;$setting&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$setting&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Reverse the migrations.
     *
     * @return void
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Setting&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'emails'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'settingable_type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'team'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Approach #2 is to extend the migration class to make it easier to add/remove data. I have used this approach when managing permissions using migrations. That might look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;
&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Core\Application&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Authentication\Permissions\Permission&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;&lt;span class="nc"&gt;Illuminate\Database\Migrations\Migration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PermissionMigration&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Migration&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;up&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$permission&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;final&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;down&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Permission&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;whereIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'key'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getPermissions&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever you want to add permissions you just need to create a new migration that extends the permission migration and define an array of permission keys to be added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Authentication\Permissions\CreatePost&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Core\Application\PermissionMigration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AddCreatePostPermission&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;PermissionMigration&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$permissions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;CreatePost&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$key&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is an incomplete example, you'd want to build ways to update and remove permissions, but I hope you get the idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Adding attributes to the request
&lt;/h2&gt;

&lt;p&gt;You can add attributes to Laravel's request object using middleware. One scenario in which this is handy, is in mulit-tenant applications where you want to fetch a given team or organization and make sure the requesting user has access to it, as well as passing along the entity so you don't have to look it up multiple times.&lt;/p&gt;

&lt;p&gt;Here is what the middleware might look like. If you are copying this at home, be aware that the &lt;code&gt;$user-&amp;gt;cannot()&lt;/code&gt; method is a custom helper method&lt;br&gt;
I usually add to my User model. I also use a role-based permission system, but you can use Laravel Gate's and other built-in authorization &lt;br&gt;
methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Acme\Core\Http\Middleware&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Closure&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Authentication\Permissions\Team\ViewTeam&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Acme\Team\Repositories\TeamRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Auth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Cache&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LookupTeam&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$teamRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;TeamRepository&lt;/span&gt; &lt;span class="nv"&gt;$teamRepository&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;teamRepository&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$teamRepository&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;?string&lt;/span&gt; &lt;span class="nv"&gt;$guard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;Closure&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Fetch the requesting user&lt;/span&gt;
        &lt;span class="cm"&gt;/* @var $user \Acme\Authentication\User */&lt;/span&gt;
        &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Auth&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;guard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'api'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="nv"&gt;$slug&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;teamSlug&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Fetch the requested team&lt;/span&gt;
        &lt;span class="nv"&gt;$team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;teamRepository&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$slug&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'slug'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// If no team is found, return a 404&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;abort&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Make sure user has access&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;cannot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ViewTeam&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;key&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Unauthorized'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Finally, add the team to the request&lt;/span&gt;
        &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'team'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure to add the middleware to the route middleware group in your Kernel.php file, then you can attach the middleware to your route groups&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/team/{teamSlug}'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'team-lookup'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;group&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/tasks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;TaskController&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'get'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in the controller method, you can retrieve the Team from the request object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Request&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;TaskResource&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$team&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;attributes&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'team'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nv"&gt;$tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dispatch_now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GetTeamTasks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$team&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;TaskResource&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$tasks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  6. Ordering models by distant many-to-many related items
&lt;/h2&gt;

&lt;p&gt;Let's say you're building a system that tracks and manages production chains. When assigning products to machines, you want&lt;br&gt;
to get a list of available machines ordered by what products they support, with the most compatible at the top of the list.&lt;/p&gt;

&lt;p&gt;You might have a Machine entity that belongs to a Machine Type. The Machine Type entity has a Many-to-Many relationship with&lt;br&gt;
Products.&lt;/p&gt;

&lt;p&gt;So you need to do a count and order based on a many-to-many relationship with the assigned Machine Type. You can use &lt;code&gt;withCount&lt;/code&gt; with constraints&lt;br&gt;
to order the machine results based on whether or not the machine's type relationship has the assigned products you're looking for.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$machines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$machines&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withCount&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;whereHas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'products'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$query&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'products.id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}])&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'type_count'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'desc'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whether or not the assigned type has the assigned products will set the type_count to a 0 or a 1, which you can then order the results by.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I hope you found some of these tips useful. Feel free to add your thoughts, comments, criticisms, or ideas below! &lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://mattdoescode.com/articles/six-laravel-tips-2019-10-20"&gt;6 Laravel Tips&lt;/a&gt; appeared first on &lt;a href="https://mattdoescode.com"&gt;Matt Does Code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>php</category>
      <category>laravel</category>
      <category>beginners</category>
    </item>
    <item>
      <title>API Specifications and Laravel</title>
      <dc:creator>Matt Moore</dc:creator>
      <pubDate>Wed, 14 Nov 2018 16:09:35 +0000</pubDate>
      <link>https://dev.to/mattnmoore/api-specifications-and-laravel-2o9g</link>
      <guid>https://dev.to/mattnmoore/api-specifications-and-laravel-2o9g</guid>
      <description>&lt;p&gt;One of the most important parts of building an API, or any codebase for that matter, is making sure it is well-documented. How can users know how to use your API, or what it even does if there’s no documentation? How can your team members (or yourself 6 months from now) know how to extend and test your endpoints if there’s nothing describing how they’re supposed to behave? &lt;/p&gt;

&lt;p&gt;The biggest hurdle with documentation in my experience is maintaining them. What happens when someone is in a rush to build a feature and they forget to add it to the docs? Or when business rules change and certain inputs and outputs change? Poorly maintained documentation quickly becomes useless as users and developers no longer trust them, and suddenly it’s as if there are no docs at all, leaving them to &lt;a href="https://blog.apisyouwonthate.com/guessing-api-contracts-ac1b7eaebced" rel="noopener noreferrer"&gt;guess at contracts&lt;/a&gt;. See: &lt;a href="https://blog.codinghorror.com/the-broken-window-theory/" rel="noopener noreferrer"&gt;The Broken Window Theory&lt;/a&gt;  for why this happens.&lt;/p&gt;

&lt;p&gt;This is where specifications come in. &lt;/p&gt;

&lt;h2&gt;
  
  
  API Specification vs API Documentation
&lt;/h2&gt;

&lt;p&gt;What is an API Specification and how does it differ from documentation? &lt;a href="https://nordicapis.com/difference-api-documentation-specification-definition/" rel="noopener noreferrer"&gt;Nordic APIs has a great article that goes into the differences in detail&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Simply put, documentation explains how to use the API, while a specification describes how the API behaves. I’ve seen specifications described as blueprints for your API and I think that analogy is accurate. Indeed you can derive many things from a well-built specification including documentation, validation rules, front-end API clients, &lt;a href="https://blog.apisyouwonthate.com/tricking-colleagues-into-writing-documentation-via-contract-testing-206308b47e05" rel="noopener noreferrer"&gt;contract tests&lt;/a&gt;, and more.&lt;/p&gt;

&lt;p&gt;There are a whole host of specs to choose from, but I’m focusing on OpenAPI Version 2 (I will explain why later) and JSON Schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAPI
&lt;/h2&gt;

&lt;p&gt;Remember that we will be using &lt;a href="https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md" rel="noopener noreferrer"&gt;Open API Version 2&lt;/a&gt; for the remainder of this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generating the specification
&lt;/h3&gt;

&lt;p&gt;Open API is an API specification developed by SmartBear and can be written (or generated) as YAML or JSON files. You may also notice that when using Laravel or PHP, you can use libraries such as &lt;a href="https://github.com/DarkaOnLine/L5-Swagger" rel="noopener noreferrer"&gt;L5-Swagger&lt;/a&gt; to use annotations for generating your spec. Despite my instincts telling me this is a horrible idea I decided to give it a try. My instincts were right, it’s a horrible idea, for a number of reasons.&lt;/p&gt;

&lt;p&gt;The most readily apparent reason, though superficial, is that writing and maintaining these annotations is a chore. There’s no IDE plugins to help with formatting so you end up fiddling with asterisks, white spaces, and curly brace and comma alignment for far too long just to keep them looking nice. &lt;/p&gt;

&lt;p&gt;Aside from that, once you’re done writing the annotations, you’ll notice that they now take up the majority of your source files,add unnecessary cognitive overhead, and can become difficult to find when needed. &lt;/p&gt;

&lt;p&gt;What would be a better approach to this madness? We still need our spec to be scalable, so it can’t exist as one file. We want it to be easily navigable and editable, and we want generation of docs, tests, etc, to be straightforward.&lt;/p&gt;

&lt;p&gt;I chose to maintain my spec separately from my code in a folder labeled &lt;code&gt;spec&lt;/code&gt; in the root of my Laravel app using YAML files. Though I’m by no means a fan of YAML, I prefer writing it by hand over JSON. &lt;/p&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;

&lt;p&gt;Let’s pretend we are building a simple REST API for a blog with a few endpoints for managing articles. The endpoints might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /
GET /articles
POST /articles
GET /articles/{slug}
PUT /articles/{slug}
DELETE /articles/{slug}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Setting up the Application
&lt;/h4&gt;

&lt;p&gt;If you want to follow along, create a dev environment however you’d like to (straight on your dev machine, or using a tool like Vagrant or Docker), and install a fresh copy of Laravel.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting up the build tools
&lt;/h4&gt;

&lt;p&gt;We want to first setup all the tools and scripts necessary for building our spec. The tools I’m using are: json-refs, path-loader, js-yaml, and swagger-cli. Make sure NPM is installed and grab these packages with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save-dev json-refs path-loader js-yaml swagger-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a scripts directory in your application root and place the following script in a file called build-spec.js&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;JsonRefs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json-refs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;PathLoader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path-loader&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;YAML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;js-yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../spec/api.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="na"&gt;loaderOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="na"&gt;processContent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safeLoad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="na"&gt;location&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../spec/api.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;JsonRefs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolveRefs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../spec/dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
       &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../spec/dist/api.yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resolved&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;

       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Specification compiled successfully.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script converts the YAML files to JSON and resolves all of our external references.&lt;/p&gt;

&lt;p&gt;Finally, add the following line to the scripts section of the package.json file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"build-spec"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cd scripts &amp;amp;&amp;amp; node build-spec.js &amp;amp;&amp;amp; swagger-cli validate ../spec/dist/api.yaml"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Creating the spec object
&lt;/h4&gt;

&lt;p&gt;Now that we have our build tools setup, create the spec folder in the root of the application with a file called &lt;code&gt;api.yaml&lt;/code&gt;. According to the spec, there are three required fields. The swagger field, which specifies the version of Open API that we are using (it’s called openapi in version 3), the info field, which contains basic information about our API like it’s name and version, and the paths field, which contains our endpoint definitions. Put together, a basic spec might look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;swagger&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;2.0'&lt;/span&gt;
&lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;1.0'&lt;/span&gt;
 &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Blog API&lt;/span&gt;

&lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;api.blog.test'&lt;/span&gt;
&lt;span class="na"&gt;schemes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;consumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="na"&gt;produces&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;application/json&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./paths.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in paths.yaml, let’s create a simple endpoint to display our API version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;/&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Return&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API's version'&lt;/span&gt;
   &lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;version&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returned.'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run the build script to resolve the external references, validate the spec, and output the final product by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build-spec
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Adding the endpoint
&lt;/h4&gt;

&lt;p&gt;Let’s add the post index endpoint to our spec. I like to split out our spec into modules, following the application structure as outlined in &lt;a href="https://mattdoescode.com/scaling-laravel-architecture" rel="noopener noreferrer"&gt;Scaling Laravel Architecture&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create an articles directory, a paths subdirectory, and a YAML file called article-index.yaml. Your directory structure should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;spec
├── dist
│   └── api.yaml
├── articles
│   └── paths
│       └── article-index.yaml
├── api.yaml
└── paths.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s write our post index endpoint spec!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Return&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;list&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;articles.'&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Articles&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;page&lt;/span&gt;
   &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
   &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;limit&lt;/span&gt;
   &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
   &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
&lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Articles&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returned&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully.'&lt;/span&gt;
   &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
     &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
         &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;last_page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
         &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
           &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
               &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
             &lt;span class="na"&gt;published_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
               &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
               &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date&lt;/span&gt;
             &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
               &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
               &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
             &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
               &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then in our paths.yaml file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;/articles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./articles/paths/article-index.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above we have defined a summary of the endpoint, the available parameters, and the output schema. Path operations also inherit the &lt;code&gt;consumes&lt;/code&gt; and &lt;code&gt;produces&lt;/code&gt; field that we defined at our root level spec. We can also override them here if we’d like. &lt;/p&gt;

&lt;h4&gt;
  
  
  Extracting reusable components
&lt;/h4&gt;

&lt;p&gt;We can, and should, clean this up. You’ll notice there are some structures here that would be useful to abstract and make reusable such as pagination query parameters, metadata pagination output, and the article entity output. Extracting these structures into a reusable structure not only saves time, but allows us to maintain them in one place, rather than in every instance that they occur.&lt;/p&gt;

&lt;p&gt;OpenAPI makes defining reusable parameters easy. Add a file called &lt;code&gt;parameters.yaml&lt;/code&gt; to the root spec directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;pageParam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;page&lt;/span&gt;
 &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
 &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;

&lt;span class="na"&gt;limitParam&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;limit&lt;/span&gt;
 &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;query&lt;/span&gt;
 &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then link it api.yaml like paths.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./parameters.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To reference the objects defined here, you can reference them like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/parameters/pageParam'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the parameters section of article-index.yaml now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/parameters/pageParam'&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/parameters/limitParam'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start the ref with a # to denote it is an internal reference. Since the files resolve external references first, all of our definitions will be in the same file as our paths, so we can reference them internally.&lt;/p&gt;

&lt;p&gt;Now we need to extract our Post definition into its own schema file. According to the Open API Specification Version 2:  “Models are described using the Schema Object which is a subset of JSON Schema Draft 4.”&lt;/p&gt;

&lt;p&gt;Models may be a subset of JSON Schema, but as far as I can tell, you cannot directly work with JSON Schema objects in Open API v2. I wanted to use JSON Schema to define a single source of truth for our models, and import them into our Open API spec, but the current tools do not allow it with version 2. The awesome people over at WeWork have built &lt;a href="https://github.com/wework/speccy" rel="noopener noreferrer"&gt;Speccy&lt;/a&gt; to work with this type of setup with Open API v3, but unfortunately we are not using version 3 (We’ll get into the reasoning behind this later).&lt;/p&gt;

&lt;p&gt;So for now, we will simply use the Open API spec to define our models. I’d love to come back to this and explore JSON Schema more when there’s a viable route to do so.&lt;/p&gt;

&lt;p&gt;Create a file called &lt;code&gt;article.yaml&lt;/code&gt; in &lt;code&gt;spec/articles/schemas&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
 &lt;span class="na"&gt;published_at&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
   &lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;date&lt;/span&gt;
 &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;string&lt;/span&gt;
 &lt;span class="na"&gt;author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/definitions/Author'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now a file called &lt;code&gt;author.yaml&lt;/code&gt; in the same folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
&lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;id&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now create a file called &lt;code&gt;definitions.yaml&lt;/code&gt; in the spec/ directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;Article&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./articles/schemas/article.yaml&lt;/span&gt;
&lt;span class="na"&gt;Author&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./articles/schemas/author.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And link the definitions file in your root spec like we did with the paths and parameters files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;definitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./definitions.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can reference the models in our path operation like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Articles&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returned&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully.'&lt;/span&gt;
   &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
     &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
         &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;last_page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
           &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
             &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
         &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/definitions/Article'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could extract the meta object in the same way. Create a shared/ module in the root spec and add a schemas folder with a file called &lt;code&gt;pagination.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
&lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="na"&gt;total&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="na"&gt;last_page&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
 &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the final path operation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Return&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;list&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;of&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;articles.'&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;Articles&lt;/span&gt;
&lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/parameters/pageParam'&lt;/span&gt;
 &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/parameters/limitParam'&lt;/span&gt;
&lt;span class="na"&gt;responses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
 &lt;span class="na"&gt;200&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
   &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Articles&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;returned&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully.'&lt;/span&gt;
   &lt;span class="na"&gt;schema&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;object&lt;/span&gt;
     &lt;span class="na"&gt;properties&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;meta&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/definitions/Pagination'&lt;/span&gt;
       &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
         &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;array&lt;/span&gt;
         &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
           &lt;span class="na"&gt;$ref&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#/definitions/Article'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much cleaner! There are definitely aspects to this flow that could be improved, but I believe this is a good pattern for building a scalable and maintainable API spec. &lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation with ReDoc
&lt;/h2&gt;

&lt;p&gt;Now that we have our basic spec, let’s generate some documentation! Using &lt;a href="https://github.com/Rebilly/ReDoc" rel="noopener noreferrer"&gt;ReDoc&lt;/a&gt;, we can turn our spec into clean, easy to read docs. First, grab redoc-cli by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g redoc-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then add the following to the scripts section in the &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"serve-docs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"redoc-cli serve spec/dist/api.yaml --watch"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now serve up your docs by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run docs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to &lt;a href="http://127.0.0.1:8080" rel="noopener noreferrer"&gt;http://127.0.0.1:8080&lt;/a&gt; and you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqpwijgm3vwrkc1ykzyn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkqpwijgm3vwrkc1ykzyn.png" alt="ReDoc documentation landing page" width="800" height="417"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Easy&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing your spec
&lt;/h2&gt;

&lt;p&gt;To me, being able to test your spec against your API, and integrate that process into your CI/CD is one of the biggest benefits to having a spec in the first place. The only tool I’ve seen that does this is &lt;a href="https://github.com/apiaryio/dredd" rel="noopener noreferrer"&gt;Dredd&lt;/a&gt;, and it is the reason I suggested using Open API v2. &lt;/p&gt;

&lt;p&gt;Dredd does not yet have Open API v3 support, and a &lt;a href="https://github.com/apiaryio/dredd/issues/894" rel="noopener noreferrer"&gt;ticket has been open to add it for over a year&lt;/a&gt;. I’m not sure when to expect it, and given that there are tools to help convert from Open API v2 to v3, I think sticking with v2 to gain the benefit of Dredd is worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup
&lt;/h3&gt;

&lt;p&gt;Install Dredd using NPM&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g dredd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Initialize Dredd by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dredd init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Location of the API description document (apiary.apib) spec/dist/api.yaml
? Command to start the API server under test (npm start) 
? Host of the API under test (http://127.0.0.1:3000) http://api.blog.test
? Do you want to use hooks to customize Dredd's behavior? (Y/n) Y
  Go 
  JavaScript 
  Perl 
❯ PHP 
  Python 
  Ruby 
  Rust 
? Do you want to report your tests to the Apiary inspector? (Y/n) n
? Dredd is best served with Continuous Integration. Do you want to create CI configuration? (Y/n) N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make sure you’ve configured your app to be served at &lt;a href="http://api.blog.test" rel="noopener noreferrer"&gt;http://api.blog.test&lt;/a&gt;, or replace this with the location of your Laravel app. Next, go ahead and install the Dredd PHP hooks with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require ddelnano/dredd-hooks-php --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use these hooks to configure our application for test mode when Dredd runs. For now though, let’s see what happens when we run Dredd:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;info: Configuration './dredd.yml' found, ignoring other arguments.
info: Beginning Dredd testing...
fail: GET (200) / duration: 248ms
fail: GET (200) /articles duration: 36ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve truncated the rest of the output due to length, but as you will see, all of our tests are failing! With each failure you get the request, the expected output, and the actual output, Since we haven’t changed anything in our actual application, it doesn’t reflect what we have specced out! Let’s fix this with mocked responses.&lt;/p&gt;

&lt;h3&gt;
  
  
  Our first path
&lt;/h3&gt;

&lt;p&gt;The first path we added to our spec was the root endpoint to display our application version. It produces JSON and should output a version number. Let’s look at what Dredd tells us about this path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;request: 
method: GET
uri: /
headers: 
    Content-Type: application/json
    Accept: application/json
    User-Agent: Dredd/5.2.0 (Linux 4.15.0-38-generic; x64)

body: 

expected: 
headers: 
    Content-Type: application/json

statusCode: 200


actual: 
statusCode: 200
content-type: text/html; charset=UTF-8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I’ve truncated this as there’s tons of output, but you can see it expects a 200 response with the application/json mime-type, but it actually received a 200 response with text/html. We can quickly fix this by replacing the welcome view in the route with a JSON response like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
       &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Blog API'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="s1"&gt;'version'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'1.0'&lt;/span&gt;
   &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we re-run our tests we see that it now passes!&lt;/p&gt;

&lt;h3&gt;
  
  
  The articles endpoint
&lt;/h3&gt;

&lt;p&gt;If we look at our next test we will see that it is also failing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fail: GET (200) /articles duration: 38ms
fail: statusCode: Status code is '404' instead of '200'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The route doesn’t exist, so let’s add it by adding an entry to our routes file. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note: We would not want to put any of this directly in our routes file, it's just easier to demonstrate this way.&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we re-run Dredd, we get the following output&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fail: GET (200) /articles duration: 74ms
fail: headers: Header 'content-type' has value 'text/html; charset=UTF-8' instead of 'application/json'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get a 200 now, but the content-type is invalid. Let’s return a JSON response and see what happens.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now Dredd tells us…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fail: GET (200) /articles duration: 71ms
fail: body: At '' Invalid type: array (expected object)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are returning the correct status code and content-type, but the actual response is being marked as invalid by Dredd. Let’s look at documentation to see what Dredd is expecting:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcdxipv08r5d7o4lbij6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbcdxipv08r5d7o4lbij6.png" alt="Articles endpoint documentation in ReDoc" width="512" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that our response should be an object with a meta and data properties. Meta should contain a Pagination object as we defined in our schema, and the data property should be an array containing Article objects. Dredd validates that our API is returning the correct data structure, so let’s mock what one would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/articles'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;response&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
       &lt;span class="s1"&gt;'meta'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="s1"&gt;'page'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'total'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'last_page'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'limit'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt; 
       &lt;span class="p"&gt;],&lt;/span&gt;
       &lt;span class="s1"&gt;'data'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
       &lt;span class="p"&gt;[&lt;/span&gt;
           &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'title'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'My Article Title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'published_at'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'2018-11-13'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'body'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'My article body'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s1"&gt;'author'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
               &lt;span class="s1"&gt;'id'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="s1"&gt;'name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'Test'&lt;/span&gt;
           &lt;span class="p"&gt;]&lt;/span&gt;
       &lt;span class="p"&gt;]]&lt;/span&gt;
   &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we run Dredd, we can see all of our tests now pass!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;info: Configuration './dredd.yml' found, ignoring other arguments.
info: Beginning Dredd testing...
pass: GET (200) / duration: 174ms
pass: GET (200) /articles duration: 22ms
complete: 2 passing, 0 failing, 0 errors, 0 skipped, 2 total
complete: Tests took 198ms
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the ultimate safeguard from documentation rot! You can, and should, set up measures to prevent deployments unless your spec matches your actual API. This kind of protection around your spec is invaluable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other tools
&lt;/h2&gt;

&lt;p&gt;ReDoc and Dredd are only the beginning in terms of what you can do with your new specification. &lt;a href="https://openapi.tools/" rel="noopener noreferrer"&gt;There are tools that let you generate validation rules, client libraries, mock servers, and more!&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This article ran a bit longer than I meant it to, and I didn’t even touch on everything I wanted, so I may be writing a follow-up sometime in the future. In the meantime, please feel free to share any questions, comments, or suggestions in the section below! Thanks for reading! &lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://mattdoescode.com/api-specifications-and-laravel" rel="noopener noreferrer"&gt;API Specifications and Laravel&lt;/a&gt; appeared first on &lt;a href="https://mattdoescode.com" rel="noopener noreferrer"&gt;Matt Does Code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>api</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Scaling Laravel Architecture</title>
      <dc:creator>Matt Moore</dc:creator>
      <pubDate>Fri, 09 Nov 2018 23:08:22 +0000</pubDate>
      <link>https://dev.to/mattnmoore/scaling-laravel-architecture-2ec</link>
      <guid>https://dev.to/mattnmoore/scaling-laravel-architecture-2ec</guid>
      <description>&lt;p&gt;Laravel ships with a great starting directory structure, one which may support your entire project, depending on the size. If, however, you notice it’s getting harder and harder to find code that you want to work on, you may want to step back and rethink your app’s architecture. &lt;/p&gt;

&lt;p&gt;The most popular patterns I’ve seen in the Laravel world are Domain Driven Design and Hexagonal Architecture. While I’m by no means a DDD expert, I have found it works well within Laravel’s patterns, given you don’t try to follow it exactly. &lt;/p&gt;

&lt;p&gt;For instance, as &lt;a href="http://lorisleiva.com/conciliating-laravel-and-ddd/" rel="noopener noreferrer"&gt;this blog post&lt;/a&gt; points out, Eloquent substantially breaks DDD principles. I think the mistake here is trying to implement “pure” DDD rather than using it as a guideline.&lt;/p&gt;

&lt;p&gt;Eloquent is an Active Record ORM, and therefore is inherently incompatible with DDD. This is not a bad thing! I prefer leaning into this rather than fighting it and embracing the power Eloquent gives you alongside the benefits of DDD. &lt;/p&gt;

&lt;p&gt;I find that these Laravel components map to the following Domain-Driven Design layers quite nicely.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers/Console Command Classes  - Presentation&lt;/li&gt;
&lt;li&gt;Jobs - Application&lt;/li&gt;
&lt;li&gt;Repositories - Infrastructure&lt;/li&gt;
&lt;li&gt;Models - Domain &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Presentation
&lt;/h2&gt;

&lt;p&gt;Controllers are responsible for the presentation layer of DDD. Whether you are building an API or an application that returns HTML views, your controllers are responsible for presenting this content to the user. Custom Artisan command classes can also be considered part of the presentation layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application
&lt;/h2&gt;

&lt;p&gt;The application layer of a domain-driven codebase is responsible for orchestrating the Domain and Infrastructure layers to perform high-level tasks in your application.&lt;/p&gt;

&lt;p&gt;I like to use Laravel’s &lt;a href="https://laravel.com/docs/5.7/queues#creating-jobs" rel="noopener noreferrer"&gt;Command Bus&lt;/a&gt; for this layer. I adopted the idea from PyroCMS, and haven’t looked back since. I have also seen the Application layer represented using Gateways, &lt;a href="http://ryantablada.com/post/two-design-patterns-that-will-make-your-applications-better" rel="noopener noreferrer"&gt;which is outlined in this post&lt;/a&gt;, but I think encapsulating features into a single job class is cleaner. &lt;/p&gt;

&lt;p&gt;A big benefit of using Jobs is that you can dispatch them from any presentation layer. Just make sure you use dispatch_now() function so it doesn’t get queued.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dispatch_now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreatePost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Infrastructure
&lt;/h2&gt;

&lt;p&gt;The infrastructure layer deals with anything that interacts with code or services outside of the application. This includes things like emails, API calls, and,most commonly, database interactions. I am a huge fan of the &lt;a href="https://medium.com/employbl/use-the-repository-design-pattern-in-a-laravel-application-13f0b46a3dce" rel="noopener noreferrer"&gt;repository pattern&lt;/a&gt;  for interacting with the database in a Laravel application. Encapsulating query logic and model retrieval is a sure way to reduce bugs and promote code reuse for database interactions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Domain
&lt;/h2&gt;

&lt;p&gt;The domain layer contains all business logic and is the heart of your application. This is the layer that can get muddy when using Eloquent since your domain models know about your database. If we ignore this aspect, and only use repositories to interact with the database, I believe we can satisfy the requirement of separating these concerns sufficiently. &lt;/p&gt;

&lt;p&gt;I’ve seen hacks in Eloquent to disable database calls but I believe this is unnecessary. I find that baking these standards into the project at the documentation/code review level is sufficient. &lt;/p&gt;

&lt;p&gt;An alternative to Eloquent is using &lt;a href="https://www.laraveldoctrine.org/" rel="noopener noreferrer"&gt;Laravel Doctrine&lt;/a&gt;. This gives you everything you need to create a true Domain layer using Entities and a data-mapper for the infrastructure layer. There are a number of benefits to this approach when working on a truly large application, but it might be overkill for smaller applications.&lt;/p&gt;

&lt;p&gt;I typically enjoy Eloquent, especially for the speed it provides when you’re hacking together a prototype or proof of concept, and believe it can even work fine for large applications. I have, however, experienced some of its shortcomings first hand, and think that in certain situations, an alternative such as Data Mapper is a completely valid choice. It’s important that you always weigh your options and pick the right tool for the job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.thoughtfulcode.com/orm-active-record-vs-data-mapper/" rel="noopener noreferrer"&gt;Here is a fantastic article that takes an honest look at both patterns and their tradeoffs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Okay, so what does this actually look like in a Laravel application? Let’s go through the steps I typically take when starting  a new project following this architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set-up
&lt;/h2&gt;

&lt;p&gt;Let’s say we want to build a personal site with a blog and a projects section. Let’s call it our Portfolio. &lt;/p&gt;

&lt;p&gt;Note: A site this small would work fine with the default directory structure and basic Laravel architecture, but ignore that for now. &lt;/p&gt;

&lt;p&gt;Download a fresh copy of Laravel using either composer create-project or the laravel CLI as outlined &lt;a href="https://laravel.com/docs/5.7/installation" rel="noopener noreferrer"&gt;in the documentation.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Namespace your app using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan app:name Portfolio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Moving the core code.
&lt;/h2&gt;

&lt;p&gt;Your initial app directory structure should look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── Console
│   └── Kernel.php
├── Exceptions
│   └── Handler.php
├── Http
│   ├── Controllers
│   │   ├── Auth
│   │   │   ├── ForgotPasswordController.php
│   │   │   ├── LoginController.php
│   │   │   ├── RegisterController.php
│   │   │   ├── ResetPasswordController.php
│   │   │   └── VerificationController.php
│   │   └── Controller.php
│   ├── Kernel.php
│   └── Middleware
│       ├── Authenticate.php
│       ├── CheckForMaintenanceMode.php
│       ├── EncryptCookies.php
│       ├── RedirectIfAuthenticated.php
│       ├── TrimStrings.php
│       ├── TrustProxies.php
│       └── VerifyCsrfToken.php
├── Providers
│   ├── AppServiceProvider.php
│   ├── AuthServiceProvider.php
│   ├── BroadcastServiceProvider.php
│   ├── EventServiceProvider.php
│   └── RouteServiceProvider.php
└── User.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I first like to  move all the core code into a Core\ namespace. This contains all the laravel specific setup code such as the main service provider, kernel, etc. &lt;/p&gt;

&lt;p&gt;To do this, create a Core folder in the app/ directory and move everything into it except the User model. Either using an IDE, or by hand, you must now adjust the namespaces of all the classes within these directories. Simply add the Core namespace after Portfolio\ like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Portfolio\Core\Providers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once namespaces are adjusted, we have to fix a few references.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;bootstrap/app.php&lt;/strong&gt;&lt;br&gt;
Fix the singleton bindings for the HTTP and Console Kernels, as well as the Exception handler.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;config/app.php&lt;/strong&gt;&lt;br&gt;
Fix the references to your application service providers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;app/Core/Http/Kernel.php&lt;/strong&gt;&lt;br&gt;
Fix the middleware references for the &lt;code&gt;CheckForMaintenaceMode&lt;/code&gt;, &lt;code&gt;TrimStrings&lt;/code&gt;, &lt;code&gt;TrustProxies&lt;/code&gt;, &lt;code&gt;EncryptCookies&lt;/code&gt;, &lt;code&gt;VerifyCsrfToken&lt;/code&gt; middlewares, as well as the &lt;code&gt;Authenticate&lt;/code&gt; and &lt;code&gt;RedirectIfAuthenticated&lt;/code&gt; route middlewares. These references can be simplified by simply prepending the middleware class with the &lt;code&gt;Middleware\&lt;/code&gt; namespace e.g. &lt;code&gt;Middleware\CheckForMaintenanceMode::class&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;app/Core/Providers/RouteServiceProvider.php&lt;/strong&gt;&lt;br&gt;
Fix the &lt;code&gt;$namespace&lt;/code&gt; attribute to allow for multiple controller directories. I prefer to shorten this to just the route namespace, in this case &lt;code&gt;Portfolio&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;app/Core/Console/Kernel.php&lt;/strong&gt;&lt;br&gt;
Remove the call to &lt;code&gt;load()&lt;/code&gt; (line 38) as commands will be declared in numerous places. I prefer to declare commands explicitly using the &lt;code&gt;$commands&lt;/code&gt; attribute, or you can use the newer console route file.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You now have a clean slate to build your first feature module. Your app/ directory structure should now look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Core
    ├── Console
    ├── Exceptions
    ├── Http
    │   ├── Controllers
    │   │   └── Auth
    │   └── Middleware
    └── Providers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Blog Module
&lt;/h2&gt;

&lt;p&gt;Let’s start the Blog module. Every module requires some of the same components. Controllers (presentation), Jobs (application), Models (domain), and Repositories (infrastructure). I like to loosely follow the default Laravel structure inside each Module like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Blog
├── Http
│   ├── Controllers
│   │   └── PostController.php
│   ├── Requests
│   │   ├── CreateOrUpdatePost.php
│   │   └── DeletePost.php
│   └── Transformers
│       └── PostTransformer.php
├── Jobs
│   ├── EditPost.php
│   ├── RemovePost.php
│   └── WritePost.php
├── Repositories
│   ├── EloquentPostRepository.php
│   └── PostRepository.php
├── Author.php
├── Comment.php
└── Post.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The presentation layer lives in Http/ and Console/. This is where you will find your controllers, form requests and transformers (I recommend &lt;a href="https://fractal.thephpleague.com/" rel="noopener noreferrer"&gt;Fractal&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The bulk of the application layer can be found in in the Jobs directory. The only thing your Jobs should do is delegate to lower layers such as Repositories and Service classes. No business logic should live here.&lt;/p&gt;

&lt;p&gt;The repositories directory seems self-explanatory, this is where your repositories live.&lt;/p&gt;

&lt;p&gt;Models are in the root of the module. I prefer this structure because it’s where most of the business logic should live, which should be the most visible and readily available part of any module.  Any other service classes could live here as well, or you might opt to put them in a Service or Utilities namespace. &lt;/p&gt;

&lt;p&gt;While this is a very basic module, I believe it demonstrates the idea of how you can shape a Laravel application with principles from DD. You can freely implement any other Laravel component in the same way, for instance Events or Listeners would become directories in the root of the module, as would Notifications or Mail classes. &lt;/p&gt;

&lt;p&gt;If your module starts to become too large you can split it out into submodules, but I recommend doing everything you can to keep your directory tree as flat as possible. Only nest when it is the cleanest solution! Having 5 submodules with 1 model each is probably overkill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Project Module
&lt;/h2&gt;

&lt;p&gt;Our “Projects” module will look very similar in structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Projects
├── Http
│   ├── Controllers
│   │   └── ProjectController.php
│   ├── Requests
│   │   ├── CreateOrUpdateProject.php
│   │   └── DeleteProject.php
│   └── Transformers
│       └── ProjectTransformer.php
├── Jobs
│   └── CreateProject.php
├── Repositories
│   ├── EloquentProjectRepository.php
│   └── ProjectRepository.php
└── Project.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Extracting Comments into its own module
&lt;/h2&gt;

&lt;p&gt;Let’s imagine that we want to enable comments in our Project module. Currently the comment code lives in the Blog module, so we must refactor it into a shared module. &lt;/p&gt;

&lt;p&gt;Shared modules can either live inside the Core namespace or a top-level module of its own. Or you might want to create a Shared module with utility classes, traits, or sub-modules. Any of these are perfectly valid and will depend on a multitude of factors.&lt;/p&gt;

&lt;p&gt;Let’s create a top-level Comments module  for both the Blog and Project modules to consume.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Comments
├── Jobs
│   ├── CreateComment.php
│   ├── RemoveComment.php
│   └── UpdateComment.php
├── CommentController.php
├── Comment.php
├── CommentRepository.php
└── EloquentCommentRepository.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how the model, controller, and repository live in the root module directory. This is just personal preference. If there is only one type of a component, I will not put it in its own directory as it only makes it harder to get to the file. I only start to split things into their own directories when a directory gets too big to easily grok. It might not be the best architecture pattern but it has worked well for me so far. Do what feels best for you, but the important thing is to remain consistent! Don’t go by feel alone, create rules for organizing files so that other people who work on the project can replicate your organization. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In the future I want to dig deeper into what this architecture pattern looks like at the code-level but I hope I’ve shed some light on how you can organize a growing project using Laravel effectively.&lt;/p&gt;

&lt;p&gt;I’m currently reading &lt;a href="https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215" rel="noopener noreferrer"&gt;Domain Driven Design&lt;/a&gt; and recommend it to anyone looking to learn more about DDD. I’m by no means an expert on this topic and it is something I’m constantly striving to improve at. If you have any suggestions or want to point out any flaws in anything I’ve demonstrated, please feel free to do so in the comments. Thanks for reading!&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://mattdoescode.com/scaling-laravel-architecture" rel="noopener noreferrer"&gt;Scaling Laravel Architecture&lt;/a&gt; appeared first on &lt;a href="https://mattdoescode.com" rel="noopener noreferrer"&gt;Matt Does Code&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Angular, Accessibility, and You</title>
      <dc:creator>Matt Moore</dc:creator>
      <pubDate>Thu, 25 Oct 2018 20:44:39 +0000</pubDate>
      <link>https://dev.to/mattnmoore/angular-accessibility-and-you-12g9</link>
      <guid>https://dev.to/mattnmoore/angular-accessibility-and-you-12g9</guid>
      <description>&lt;p&gt;The motivation behind this post is that technical resources for implementing accessibility techniques, especially with modern Javascript frameworks like Angular, are very sparse. There also seems to be a misconception that modern Javascript frameworks impede your ability to make your web application accessible. While there are some accessibility pitfalls involved in using frameworks like Angular, there are also many benefits, and I want to go over some of the lessons I’ve learned while building an Angular powered platform that strives to be as accessible as possible.&lt;/p&gt;

&lt;p&gt;I also want to point out that there are many aspects to web accessibility, but this article focuses on keyboard and screen reader optimizations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;SPA Considerations

&lt;ol&gt;
&lt;li&gt;Route changes&lt;/li&gt;
&lt;li&gt;Form validation&lt;/li&gt;
&lt;li&gt;Lazily-loaded content&lt;/li&gt;
&lt;li&gt;Notifications&lt;/li&gt;
&lt;li&gt;Page title&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;UI Package Pitfalls

&lt;ol&gt;
&lt;li&gt;Data table&lt;/li&gt;
&lt;li&gt;Bootstrap&lt;/li&gt;
&lt;li&gt;Tree Components&lt;/li&gt;
&lt;li&gt;Toggle Switches&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Recipes

&lt;ol&gt;
&lt;li&gt;Skip Link&lt;/li&gt;
&lt;li&gt;Focus management&lt;/li&gt;
&lt;li&gt;Page titles&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  SPA Considerations
&lt;/h2&gt;

&lt;p&gt;It doesn’t matter what technology you use, if you’re building a Single-Page Application (SPA), there are some extra considerations you must make to ensure that it is accessible. In this section, we’ll briefly cover some of these areas. Later, in the Recipes section, we’ll get into the details of how to solve these concerns using Angular.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Route Changes
&lt;/h3&gt;

&lt;p&gt;The biggest difference between a traditional web application and an SPA is dealing with navigation. In a traditional web application, on each page change and on most user interactions such as form submissions, the web page reloads, focus gets reset, and the page title changes (if you are using proper page titles). If your user is using a screen reader, it will announce the new page title, and it will make them aware that the new page has loaded. In an SPA, you must manage this manually.&lt;/p&gt;

&lt;p&gt;I’ve seen a few ways to accomplish this, but the easiest way to do it is to set focus to each page’s H1 element when it comes on screen. I will go over how to do this with Angular later on.&lt;/p&gt;

&lt;p&gt;Another option is to have a div with specific wording to show a new page has loaded, which only appears on screen readers. Something like “The contact page is now on-screen”, and set focus to that div on each route change.&lt;/p&gt;

&lt;p&gt;You could also set focus to the skip link or header on each route change to emulate how a traditional web application behaves. These are all valid options, but best practice will depend on your specific use-case.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Form Validation
&lt;/h3&gt;

&lt;p&gt;Form validation is another important area to consider when building an accessible SPA. Similar to route changes, focus management is key here. To ensure a good user experience, make sure that focus gets set to any error messages after submission. Useful error messages are clearly linked to a specific input field, with clear directions for fixing it.&lt;/p&gt;

&lt;p&gt;Another common issue I’ve noticed with SPA forms is that the submit button is disabled until the form is valid. Don’t do this! Your user should be able to submit your forms in any state, and if the form is invalid, it should provide clear direction on how to fix it. This will greatly improve usability for screen reader and non screen reader users alike.&lt;/p&gt;

&lt;p&gt;Here is a great post about implementing accessible forms using Angular: &lt;a href="https://simplyaccessible.com/article/accessible-forms-angular/"&gt;https://simplyaccessible.com/article/accessible-forms-angular/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lazily-loaded content
&lt;/h3&gt;

&lt;p&gt;This is a big one, and one you don’t usually have to even think about for traditional web apps. There are a wide range of solutions for solving this issue, and it’s one that I’m still refining on Dinolytics.&lt;/p&gt;

&lt;p&gt;Lazy-loading all your content is a very popular method for SPA’s as it dramatically improves the initial page load. If you have lots of different content areas, you can split a giant API call into several smaller ones. The problem is that this content will not get presented to screen reader users. If they’re on a slower connection, they may have explored the page before the content gets loaded and concluded that it’s an empty page.&lt;/p&gt;

&lt;p&gt;The best solution I’ve found involves using aria-live regions. You can use an aria-live region as a way to notify screen reader users when certain content has loaded. Do not, however, just throw all your content into an aria live region, this will cause your entire page to be read when it gets loaded in. Stick with short descriptive messages such as “content loading” and “content is now on-screen”. If in doubt, test with a screen reader!&lt;/p&gt;

&lt;p&gt;If you’d like to read more about aria-live regions and the available options, check out this article: &lt;a href="http://juicystudio.com/article/wai-aria_live-regions_updated.php"&gt;http://juicystudio.com/article/wai-aria_live-regions_updated.php&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Notifications
&lt;/h3&gt;

&lt;p&gt;There are 2 main ways to handle app-wide notifications such as toast notifications for keyboard and screen reader users.&lt;/p&gt;

&lt;p&gt;The first is to use an aria-live region. You can give the aria-live attribute to your toasts container and any notifications get presented to screen readers users.&lt;/p&gt;

&lt;p&gt;The other option is to use focus. You can set focus to the notification when it appears and it will get presented to screen reader users as well. You may want to have your notification remains on-screen until it is no longer receiving focus, this will prevent the notification from being unexpectedly dismissed.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Page title
&lt;/h3&gt;

&lt;p&gt;Page titles are important for accessibility for a few reasons. Generally, it’s the first thing that gets read by screen readers when the page loads and it should give the user an idea about what’s going to be on the page.&lt;/p&gt;

&lt;p&gt;In a round-trip website or application, the page title is determined before the browser loads the page since the content is being served by the backend. If you’re building a SPA, however, you must set the page title dynamically based on the route on the front-end.&lt;/p&gt;

&lt;p&gt;In addition, a screen reader will not read the page title on subsequent page changes since the page doesn’t actually change, Javascript just swaps out the content on the same page.&lt;/p&gt;

&lt;p&gt;It is still important to manage the title, as it will be read if the user switches to a different tab and comes back, if they move to a different window, and on the first page load.&lt;/p&gt;

&lt;p&gt;If you’ve taken care of managing the page title, you will also see benefits if you switch to server-side rendering for SEO purposes since the page title will be properly set.&lt;/p&gt;

&lt;h2&gt;
  
  
  UI Package Pitfalls
&lt;/h2&gt;

&lt;p&gt;UI packages have their own section because they were, by far, my most problematic issue during my first accessibility audit on Dinolytics. In the MVP stages I was in a rapid prototype mode and I just grabbed any package that looked good and did what I needed. This included datatables, tree components, switch toggles, comboboxes and Angular bootstrap packages. At best, some of these packages had minor accessibility issues, and at worst they were completely inaccessible. Testing the accessibility of any 3rd-party package that you bring into your project is important.&lt;/p&gt;

&lt;p&gt;One options for mitigating future issues is to wrap all your 3rd-party components in your own component and use that throughout the app. This way if you ever have to switch components for any reason at all, accessibility or otherwise, you just have to change the internals of your wrapper component and the changes will be made app-wide for free. In my opinion, this is one of the biggest benefits of using something like Angular.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Datatables
&lt;/h3&gt;

&lt;p&gt;This is by far the biggest problem area when it comes to inaccessible Angular packages. I may be missing some packages and if I am, please let me know in &lt;a href="https://twitter.com/dinolytics/status/1055564328982597632"&gt;the Twitter thread&lt;/a&gt;, but out of the few times I went searching, I only found 1 package that met all of our requirements and was even remotely accessible. There are still a few minor accessibility and responsive issues with this package, and I’ve forked it to make some improvements. The fork is not on NPM yet but I am planning on publishing it soon. In the meantime, you can check out the original package as it’s by far the best Angular Datatable package in terms of accessibility.&lt;/p&gt;

&lt;p&gt;Original:  &lt;a href="https://github.com/brunano21/angular-4-data-table#readme"&gt;https://github.com/brunano21/angular-4-data-table#readme&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Fork:  &lt;a href="https://github.com/pope-tech/ngx-table"&gt;https://github.com/pope-tech/ngx-table&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Bootstrap
&lt;/h3&gt;

&lt;p&gt;Dinolytics uses Bootstrap which has great accessibility support, but there are multiple Angular packages that implement the Javascript based components such as toggletips and modals. I didn’t notice until I already implemented most of the components that the one I chose was completely inaccessible. Luckily, there is an alternative that has great accessibility support built-in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ng-bootstrap.github.io/#/home"&gt;https://ng-bootstrap.github.io/#/home&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  3. Tree Components
&lt;/h3&gt;

&lt;p&gt;Dinolytics presents a tree component to help you manage your group hierarchy. There are a few tree components for Angular out there, but I only found one that supports keyboard navigation. This is a great example of why you should employ multiple forms of accessibility testing.&lt;/p&gt;

&lt;p&gt;I thought the fact that the tree was keyboard-navigable was enough to consider it accessible. It turns out there was no way to navigate to the tree by keyboard only, which I should have caught during testing. In addition, it wasn’t presenting any content to screen readers even after being focused. It was completely inaccessible and I wasn’t even aware until I tested with a screen reader.&lt;/p&gt;

&lt;p&gt;Since there wasn’t any other package (even the Angular Material tree component is completely inaccessible!), I decided to fork this package and add aria support. This forked version is what we’re currently using on Dinolytics, and while it’s not yet perfect, it’s at least usable. I am planning on submitting a PR to make these changes available to everyone in the near future.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/500tech/angular-tree-component"&gt;https://github.com/500tech/angular-tree-component&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Toggle switches
&lt;/h3&gt;

&lt;p&gt;I am a fan of using &lt;a href="https://github.com/uncommonconcept/ngx-toggle-switch"&gt;toggle switches &lt;/a&gt;rather than checkboxes. I think that they look better and are easily understood by the user. That being said, all the toggle switch packages for Angular that I could find are inaccessible. While you can accomplish the same look and feel using CSS and Javascript, which we might do in the future, I decided to change all the toggle switches to checkboxes. Sometimes just using native HTML elements is the best option for remediating some of the issues you run into when you override native browser behavior.&lt;/p&gt;
&lt;h2&gt;
  
  
  Recipes
&lt;/h2&gt;

&lt;p&gt;Let’s dive into some code. I want to go over some common accessibility techniques and how you can implement them in Angular.&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Skip Link
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://webaim.org/techniques/skipnav"&gt;WebAIM has a great article on skip links&lt;/a&gt; so I won’t explain the benefits here. I initially thought you could implement this using Angular’s routerLink and fragment directives like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;a [routerLink]="['./']" fragment="main-content"&amp;gt;Skip to content&amp;lt;/a&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This doesn’t work! If you activate that link, nothing happens. I tried a lot of combinations using native attributes but nothing worked. The thing that finally got it working was the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div id="skip-link"&amp;gt;
    &amp;lt;a [href]="skipLinkPath"&amp;gt;Skip to content&amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;


&amp;lt;main id="main-content" class="content"&amp;gt;
    &amp;lt;!--Main content goes here--&amp;gt;
&amp;lt;/main&amp;gt;

// in constructor or ngOnInit()
router.events.pipe(filter(event =&amp;gt; event instanceof NavigationEnd)).subscribe(() =&amp;gt; {
   if( ! this.router.url.endsWith('#main-content')) {
       this.skipLinkPath = `${this.router.url}#main-content`;
   }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also found a blog post with an alternate method. I personally prefer the method above since it’s as close to a native skip link as possible, but the following, which uses a button and calling the focus method on the HTML element itself, works as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://markleblog.com/tl-dr/"&gt;http://markleblog.com/tl-dr/&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Focus Management
&lt;/h3&gt;

&lt;p&gt;Focus management is a huge piece of web accessibility, especially when it comes to SPA’s. There are many interactions which change what’s on screen, and you need to make sure your app focuses on those elements appropriately. There are a few techniques you can employ using Angular to manage focus.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 1:
&lt;/h4&gt;

&lt;p&gt;Let’s say you have a content or form section that is initially hidden, and comes into view when the user presses a button.&lt;/p&gt;

&lt;p&gt;Take for instance, the website widget on the group screen in Dinolytics. The initial view is showing the websites list.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6lCL_0Ua--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/websites-table.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6lCL_0Ua--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/websites-table.png" alt="" width="512" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When the user activates the “Add Website” button, the screen changes to the website form. When interactions like this happen, you need to make sure you are setting focus to the appropriate element, in this case the first and only field in the form.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QVLLDA_B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/websites-form.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QVLLDA_B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/websites-form.png" alt="" width="512" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can accomplish this in Angular in the following way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;div&amp;gt;
   &amp;lt;button type="button" (click)="toggleForm()"&amp;gt;
       &amp;lt;ng-container *ngIf=" ! showForm"&amp;gt;Show form&amp;lt;/ng-container&amp;gt;
       &amp;lt;ng-container *ngIf="showForm"&amp;gt;Back&amp;lt;/ng-container&amp;gt;
   &amp;lt;/button&amp;gt;

   &amp;lt;ng-container *ngIf=" ! showForm"&amp;gt;
       &amp;lt;table id="mytable"&amp;gt;&amp;lt;/table&amp;gt;
   &amp;lt;/ng-container&amp;gt;

   &amp;lt;ng-container *ngIf="showForm"&amp;gt;
       &amp;lt;form&amp;gt;
           &amp;lt;label&amp;gt;Website&amp;lt;/label&amp;gt;
           &amp;lt;input type="text" id="website" name="website" /&amp;gt;
       &amp;lt;/form&amp;gt;
   &amp;lt;/ng-container&amp;gt;

&amp;lt;/div&amp;gt;


public toggleForm() {
   this.showForm = ! this.showForm;

   let focus = this.showForm ? 'website' : 'mytable';

   setTimeout(() =&amp;gt; {
       document.getElementById(focus).focus();
   });
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things are going on here. &lt;a href="https://blog.angular-university.io/angular-ng-template-ng-container-ngtemplateoutlet/"&gt;First, if you don’t know about ng-container, go check it out!&lt;/a&gt; It provides a convenient way to use structural directives without adding unnecessary divs and spans.&lt;/p&gt;

&lt;p&gt;Second, you may have noticed that the focus() call is wrapped in a setTimeout() function. This is because the browser needs to perform an update before calling the focus method or else the element you’re trying to focus on won’t be on-screen and it will fail.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario 2:
&lt;/h4&gt;

&lt;p&gt;You are using dynamic form inputs where the user can add or remove inputs by activating a button. Take the external email addresses field on the reports screen in Dinolytics for instance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_vgjy6_e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_vgjy6_e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-1.png" alt="" width="398" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The interface starts with the “Send to external email addresses” button. When you activate that button it adds a new text input for an e-mail address.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ogNFF8MC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ogNFF8MC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-2.png" alt="" width="401" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a new field gets added it should receive focus.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ViwRsXEw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ViwRsXEw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/external-emails-3.png" alt="" width="447" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a field is removed, the previous field should receive focus, and when all fields are removed, the “Send to external email addresses” button should receive focus. You can accomplish a large part of this with a custom directive on your dynamic input field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;input focus-input formControlName="address" id="emails-{{ ii }}" class="form-control" type="email" name="emails[]" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { AfterViewInit, Directive, ElementRef } from "@angular/core";

@Directive({
   selector: '[focus-input]'
})
export class FocusInput implements AfterViewInit {

   constructor(public elem: ElementRef) {}

   ngAfterViewInit() {
       this.elem.nativeElement.focus();
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes care of setting focus to the input when it is added. Now we have to make sure that focus is returned to the previous element when an input is removed. We can just grab the index of the input being removed, subtract one, and focus to that id. Now add a call to focus on the main button when all emails get removed and you’re done!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public deleteEmail(index) {

   // remove email field

   // set focus
   document.getElementById('emails-' + (index - 1)).focus();
}

public removeAllExternalEmails() {

   // remove all emails and hide container

   // set focus
   document.getElementById('show-external-emails').focus();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Scenario 3:
&lt;/h4&gt;

&lt;p&gt;The route changes and you want to focus on the H1 tag. We can hook into the router events again to make sure this happens on every route change automatically.&lt;/p&gt;

&lt;p&gt;Make sure your H1’s are focusable by setting tabindex=”-1″ and then subscribe to the router events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(private router: Router) {
    router.events.pipe(filter(event =&amp;gt; event instanceof NavigationEnd)).subscribe(() =&amp;gt; {
        document.getElementsByTagName('h1')[0].focus();
    });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Scenario 4:
&lt;/h4&gt;

&lt;p&gt;You want to set focus to an Angular component but can’t use a tag name, id, or class. I ran into this when I tried to focus on a combobox component using the &lt;a href="https://github.com/ng-select/ng-select"&gt;ng-select package&lt;/a&gt;. We can accomplish using Angular’s View Child decorator. I suggest only using this method when a more native approach like using document.getElementById is not available.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
&amp;lt;ng-select #websiteSelect
          [items]="selectWebsites$ | async"
          formControlName="website"
          placeholder="Select a website"
          bindLabel="name"
          labelForId="website"&amp;gt;
&amp;lt;/ng-select&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ViewChild('websiteSelect') websiteSelect;

public toggleForm() {
   setTimeout(() =&amp;gt; {
       this.mySelect.focus();
   });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can pass a component class or string identifier into ViewChild which is defined by declaring it on the component prepended by a ‘#’ like the example above. You can then access that component directly. Note that the setTimeout() call is only needed if the component was not on screen before the toggle call.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Page Titles
&lt;/h3&gt;

&lt;p&gt;Angular comes with a class to help you manage your page title. I hooked into the route definition so that it was automatically defined based on the route.&lt;/p&gt;

&lt;p&gt;You can define the page title on the route, and then subscribe to navigation change events through the router.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;constructor(private router: Router,
                   private route: ActivatedRoute
                   private titleService: Title) {

   router.events.pipe(filter(event =&amp;gt; event instanceof NavigationEnd)).subscribe(() =&amp;gt; {
       let title = this.getTitleFromRoute(route.root) + ' - Dinolytics';
       this.titleService.setTitle(title);
   });
}

private getTitleFromRoute(route) {
   if (route.snapshot.data.hasOwnProperty('title')) {
       return route.snapshot.data.title;
   }

   let children: ActivatedRoute[] = route.children;

   // iterate over route children
   for (let child of children) {
       // verify that we have the correct router outlet
       if (child.outlet !== PRIMARY_OUTLET) {
           continue;
       }

       if ( ! child.snapshot.data.hasOwnProperty('title')) {
           return this.getTitleFromRoute(child);
       }

       return child.snapshot.data.title;
   }

   return false;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const routes = [{
   path: ':id',
   component: GroupsEditComponent,
   data: {
       title: 'Edit Group'
   },
}]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since routes can be nested, we must recursively iterate over the routes to find the title. Once we have it we can use Angular’s TitleService to set the correct title.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;Now that you know a few tips and tricks to help make your Angular app more accessible, you need to know how to test them.&lt;/p&gt;

&lt;h3&gt;
  
  
  WAVE
&lt;/h3&gt;

&lt;p&gt;The first and easiest method to use is the WAVE browser extension.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/wave-evaluation-tool/jbbplnpkjmmeebjpijfedlgcdilocofh?hl=en-US"&gt;WAVE Chrome Extension&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/wave-accessibility-tool/"&gt;WAVE Firefox Extension&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can locally evaluate each page using this extension to quickly find points of failure and remediate them. You will not find all the issues with your application using this method but it will get you started.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Axe&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Axe also has free browser extensions to get you started with initial accessibility assessments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/axe/lhdoppojpmngadmnindnejefpokejbdd"&gt;Axe Chrome Extension&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/"&gt;Axe Firefox Extension&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyboard Testing
&lt;/h3&gt;

&lt;p&gt;The next method is to test your application using your keyboard only. &lt;a href="https://webaim.org/techniques/keyboard"&gt;WebAIM has an awesome article to help get you started with this technique&lt;/a&gt;. If you cannot effectively use your app without a mouse, it’s not accessible! Make sure you use proper focus management and indicators to help improve keyboard navigation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Screen Reader Testing
&lt;/h3&gt;

&lt;p&gt;The final method I will recommend is screen reader testing. &lt;a href="https://webaim.org/articles/screenreader_testing"&gt;Again, WebAIM has great resources for helping you with this&lt;/a&gt;. Once you’re familiar with how the screen reader works, turn off your monitor and try to use your application. You will quickly find which areas need work.&lt;/p&gt;

&lt;h4&gt;
  
  
  Windows
&lt;/h4&gt;

&lt;p&gt;Windows users can use &lt;a href="https://www.nvaccess.org/"&gt;NVDA&lt;/a&gt; and Firefox, Chrome, or IE with very little setup.&lt;/p&gt;

&lt;h4&gt;
  
  
  Mac
&lt;/h4&gt;

&lt;p&gt;Mac has VoiceOver already installed and ready to go.&lt;/p&gt;

&lt;h4&gt;
  
  
  Linux
&lt;/h4&gt;

&lt;p&gt;If you are a Linux user like myself, there are a few options available to you.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;Chromevox&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://chrome.google.com/webstore/detail/chromevox/kgejglhpjiefppelpmljglcjbhoiplfn?hl=en"&gt;Link to Chromevox in the Google app store.&lt;/a&gt; I don’t recommend this option as there seem to be a lot of issues with ChromeVox and it doesn’t have very high adoption as of now.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;Linux screen reader such as Orca&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;I haven’t tested any of these out yet but they are on my list to check out.&lt;/p&gt;

&lt;h5&gt;
  
  
  &lt;strong&gt;NVDA using VirtualBox&lt;/strong&gt;
&lt;/h5&gt;

&lt;p&gt;Finally, the method I use employs a Windows VirtualBox image running Firefox, Chrome, and NVDA. I will briefly walk you through setting this up as there are a few gotchas.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Head over to &lt;a href="https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/"&gt;https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/&lt;/a&gt; and get a Windows 10 image by selecting the “MSEdge on Win10” machine on the VirtualBox platform.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you don’t already have VirtualBox, go to &lt;a href="https://www.virtualbox.org/"&gt;https://www.virtualbox.org/&lt;/a&gt; and download the appropriate package for your machine and install it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Once your image has finished downloading and you have VirtualBox installed, extract the windows image .zip and import the .ova into VirtualBox by double clicking on it and boot it up.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your Angular app talks to an external API that is hosted locally, be sure to add the appropriate hostfile entries in C:\Windows\System32\drivers\etc\hosts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you’re using the Angular CLI, make sure you add a host option onto your ng serve command so that VirtualBox can talk to it. Either your internal host IP or 0.0.0.0 will work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You may not need to do anything else other than install NVDA and Firefox but if your sound is disabled like mine was, go into the machine settings and find the “Audio” section. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You may have to play with the settings as I’m under the impression it is hardware specific, but here are the settings I had to use to get mine working correctly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qf7aT4o1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/vbox-settings.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qf7aT4o1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.dinolytics.com/wp-content/uploads/2018/10/vbox-settings.png" alt="" width="512" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Host Audio Driver: PulseAudio&lt;br&gt;&lt;br&gt;
Audio Controller: Intel HD Audio&lt;br&gt;&lt;br&gt;
Enable Audio Output: Checked&lt;/p&gt;

&lt;p&gt;Save and reboot your machine and you should be good to go! Take a snapshot once everything is setup so that you can always come back to this point if something breaks (or the 90 day Windows limit is reached).&lt;/p&gt;

&lt;h3&gt;
  
  
  Automated tests
&lt;/h3&gt;

&lt;p&gt;Testing accessibility with front-end testing tools such as Jasmine and Karma is something I have yet to check out, but I really really like the idea. I think integrated accessibility checks into your test suite is a valuable practice and will protect against regressions. Here are a few resources if you’d like to dive into the topic.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://marcysutton.github.io/a11y-testing-with-angular/#/"&gt;Accessibility Testing with Angular&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://marmelab.com/blog/2018/02/22/accessibililty-testing-e2e.html"&gt;Automating accessibility testing with Selenium Webdrive and AxeCore&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://blog.angularindepth.com/test-for-accessibility-and-help-millions-of-people-97d86f72e2c4"&gt;Test for accessibility and help millions of people&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I’ve only scratched the surface of Web Accessibility in this post and there’s a ton I didn’t cover. I have included a small list of additional resources that are Angular-specific if you want to dive a bit deeper into the topic. &lt;a href="https://twitter.com/dinolytics/status/1055564328982597632"&gt;Join the conversation on Twitter&lt;/a&gt; if you have any suggestions for additional topics to cover, if you have questions, or if you just want to say hi! Thanks for reading.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://angular-2-training-book.rangle.io/handout/a11y/"&gt;Angular 2 Training Book&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://coryrylan.com/blog/angular-accessibility-tips-and-tricks"&gt;Angular Accessibility Tips and Tricks&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://marcysutton.com/slides/angular-a11y-ng-europe/#/"&gt;Accessibility with Angular&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://codeburst.io/angular-cdk-getting-started-accessibility-a11y-1b6143b961c"&gt;Angular CDK Accessibility&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://blog.dinolytics.com/2018/10/25/angular-accessibility-and-you/"&gt;Angular, Accessibility, and You&lt;/a&gt; appeared first on &lt;a href="https://blog.dinolytics.com"&gt;Dinolytics Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>a11y</category>
    </item>
  </channel>
</rss>
