<?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: Segun Olaiya</title>
    <description>The latest articles on DEV Community by Segun Olaiya (@massivebrains).</description>
    <link>https://dev.to/massivebrains</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%2F25%2Fef9be569-3ba1-4d97-b1b6-3c7ffebe37cd.png</url>
      <title>DEV Community: Segun Olaiya</title>
      <link>https://dev.to/massivebrains</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/massivebrains"/>
    <language>en</language>
    <item>
      <title>Feature testing with PHPUnit and things to avoid</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Thu, 06 Jun 2024 09:45:33 +0000</pubDate>
      <link>https://dev.to/massivebrains/feature-testing-with-phpunit-and-things-to-avoid-58ao</link>
      <guid>https://dev.to/massivebrains/feature-testing-with-phpunit-and-things-to-avoid-58ao</guid>
      <description>&lt;p&gt;I’ve had the opportunity to see many feature tests in PhpUnit that lack the fundamentals of a proper Unit test. We will discuss how to write tests properly and ensure that our tests are valuable. Before we begin, if you are unfamiliar with PHPUnit or Testing as a concept no worries, I’ll give a brief background.&lt;/p&gt;

&lt;p&gt;In today’s changing world, where we have embraced a continuous delivery and integration of our services and products, they often change frequently. Whether changed by the original author/maintainer, or by someone else. It is therefore imperative that we have some kind of safety, some tests that ensure that the behaviour of the service remains the same except intentionally modified.&lt;/p&gt;

&lt;p&gt;But there are different types of tests, Unit Tests, Feature Tests, Integration Tests, Performance Tests and so on. In this post, I want to focus on how we should write Feature tests the right way.&lt;br&gt;
Feature tests are types of tests that validate different variations of a feature. Feature tests ensure that users see and experience what you want them to experience. I believe feature tests can also qualify as integration tests.&lt;/p&gt;
&lt;h3&gt;
  
  
  Always make sure your tests are independent of each other
&lt;/h3&gt;

&lt;p&gt;let's take a scenario, where a user will call a simple get endpoint that would be handled by a service. Take a look at the test below:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OrderServiceTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&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;$user&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="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$service&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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setupBeforeClass&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&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;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                  &lt;span class="s1"&gt;'permissions'&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;service&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;OrderService&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;user&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;test_get_order_service_throws_when_user_does_not_have_access&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="nf"&gt;expectException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnauthorizedException&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="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;service&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="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;As you can see, in the &lt;code&gt;setupBeforeClass( )&lt;/code&gt; we are instatiating the service which depends on the &lt;code&gt;$user&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When you have just 1 test in this file, this is fine, however, this becomes a bad idea when you have multiple tests. The given test does not control the instatiation of the service. Therefore it is possible for other tests to modify the &lt;code&gt;$this-&amp;gt;user&lt;/code&gt; or &lt;code&gt;$this-&amp;gt;service&lt;/code&gt; while this test is running. &lt;/p&gt;

&lt;p&gt;Also, this test does not paint the full picture of an actual user journey when they try to call the order get endpoint. So to decouple the test we can have 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="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;test_get_order_service_throws_when_user_does_not_have_access&lt;/span&gt;&lt;span class="p"&gt;()&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;=&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;factory&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;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="s1"&gt;'permissions'&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="nv"&gt;$service&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;OrderService&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;user&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;expectException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;UnauthorizedException&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="nv"&gt;$service&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the test now has the complete setup of what it needs before its assertions. This test does not depend on anything else and is easy to understand what needs to exist before this exception can be thrown.&lt;/p&gt;

&lt;p&gt;Note that this does not mean that using &lt;code&gt;setupBeforeClass( )&lt;/code&gt; is bad, we can always setup things that the entire tests generally need and is guaranteed to be needed in exactly the same way like an instance of a mock.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not test too many things at once
&lt;/h3&gt;

&lt;p&gt;When we have a complex feature that does a number of things. We can easily write 1 test that handles many assertions, this makes it feel like that singular test will cover all the scenarios. - Don’t do this.&lt;/p&gt;

&lt;p&gt;Having atomic tests that focus on a single flow with a couple of assertions is more valuable and easier to understand by others.&lt;/p&gt;

&lt;p&gt;Typically, the easiest way to divide a huge feature/method to multiple independent tests is to think about all the code paths, if statements, exceptions, and external service calls and try to test them in each test.&lt;/p&gt;

&lt;p&gt;Note that the combination of all these tests eventually still gives you a full feature test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Only Mock 3rd Party services
&lt;/h3&gt;

&lt;p&gt;Mocking is a process used in testing when the feature being tested has external dependencies. The purpose of mocking is to isolate and focus on the code being tested and not on the behaviour or state of external dependencies.&lt;/p&gt;

&lt;p&gt;We should only be mocking 3rd party services in our tests, 3rd party services are external systems like APIs or SDKs that are been used in the test. These tools are what we do not have control over, hence needs mocking.&lt;/p&gt;

&lt;p&gt;Avoid mocking the Database, other methods in the application and so on. This is important because again, we are writing a feature test and not a unit test.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Huge test files
&lt;/h3&gt;

&lt;p&gt;I know this may be subjective, but it is actually good for our future selves. Imagine having a failing feature test and having to look for the test in a 4K lines of code and wondering if the test is failing because of some flaky test above or below it.&lt;/p&gt;

&lt;p&gt;If you have a major feature you can create a folder just for that feature and have different test files which would have similar test scenarios in them and are grouped together. This way - when such a scenario needs to change, it would be very clear which test needs to be included, modified or deleted in context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid tests using other features to Setup
&lt;/h3&gt;

&lt;p&gt;Tests typically follow the &lt;code&gt;GIVEN-WHEN-THEN&lt;/code&gt; approach. It is always easy to see the context given to a test in the first few lines (typically considered setup) for that test.&lt;/p&gt;

&lt;p&gt;Setup should be as basic and direct as possible. Do not use other service methods to do a setup, just because the internal implementation for that service is doing the same expected setup that is needed.&lt;/p&gt;

&lt;p&gt;The obvious reason for this is still related ot independence, your test should be as independent as possible without been at risk of failing just because a completely unrelated feature was modified. If you have to insert records to the database to set some context, do not use a register( ) method for example even though it does the same insert as you expect. You should always cary out all the setup manually without calling existing methods.&lt;/p&gt;

&lt;h3&gt;
  
  
  Avoid Logic / Code Complexities in your assertions
&lt;/h3&gt;

&lt;p&gt;When you have to do assertions that may be alot, lets say asserting that an array in a particular order, it is always a good idea to do this manually. Take a look at the set of assertions below:&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;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'One'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$reponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&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;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Two'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$reponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&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;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Three'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$reponse&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is very easy to see things like this and say, Oh, I can just do a &lt;code&gt;foreach( )&lt;/code&gt; and have 1 &lt;code&gt;$this-&amp;gt;assertEquals( )&lt;/code&gt; . Avoid that. This is because you don’t want your test carrying unnecessary logic when it should just focus on behaving as the user and as close to that as possible.&lt;br&gt;
Tests have to be clear, it needs to be as clean, simple and straightforward as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Do not expose private properties as public just because of the tests
&lt;/h3&gt;

&lt;p&gt;When a class has private properties and you do like to validate their state in a give test, avoid setting them as public. Create a getter instead.&lt;/p&gt;

&lt;p&gt;Infact, often times, these kind of properties can be implicity tested, for example, if the value of such property is eventually going to be written to the database, then you can check the database.&lt;br&gt;
When the feature itself is been highly modified just because of the tests, you should already know that something is not right.&lt;/p&gt;

&lt;p&gt;In conclusion, feature tests should always focus on ensuring that the feature is used right, it should be as simple, independent and straightforward as possible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>I tried to json_decode a string in scientific notation</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Sun, 11 Feb 2024 19:29:28 +0000</pubDate>
      <link>https://dev.to/massivebrains/i-tried-to-jsondecode-a-string-in-scientific-notation-4oem</link>
      <guid>https://dev.to/massivebrains/i-tried-to-jsondecode-a-string-in-scientific-notation-4oem</guid>
      <description>&lt;p&gt;I spent 6 hours trying to work on a bug ticket assigned to me. It turns out the code has been trying to json_decode a floating-point number in scientific notation.&lt;/p&gt;

&lt;p&gt;Okay, let me give some context, we have this method somewhere in a &lt;code&gt;Utils.php&lt;/code&gt; file:&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;function&lt;/span&gt; &lt;span class="n"&gt;is_value_empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;$value&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$has_non_empty_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;$value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$row&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="nv"&gt;$has_non_empty_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$has_non_empty_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$row&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$has_non_empty_value&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;The job of this method, in the context that it is been used, is to check if the &lt;code&gt;$value&lt;/code&gt; passed is empty. But it also needs to check the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;if &lt;code&gt;[]&lt;/code&gt; is passed, it needs to return true&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;['', '']&lt;/code&gt; is passed it still needs to return true.&lt;/li&gt;
&lt;li&gt;If a JSON encoded array with falsy values is passed it still needs to return true&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the issue we were facing was that a certain user was trying to validate if &lt;code&gt;0E86023&lt;/code&gt; was empty or not.&lt;/p&gt;

&lt;p&gt;As you can see, the first thing this method does is to attempt a &lt;code&gt;json_decode( )&lt;/code&gt;. It then checks if it successfully decodes the value. If the decoded value is not an array, it simply use the php &lt;code&gt;empty( )&lt;/code&gt; method and that's it.&lt;/p&gt;

&lt;p&gt;The issue with &lt;code&gt;0E86023&lt;/code&gt; or any floating-point number is that, if this expresssion is executed:&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="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'0E86023'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would get a floating point response from php as 0.0&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Psy Shell v0.11.22 (PHP 7.4.33 — cli) by Justin Hileman
&amp;gt; json_decode('0E86023')
= 0.0

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

&lt;/div&gt;



&lt;p&gt;But this number might look like its exactly &lt;code&gt;0.0&lt;/code&gt;. But its not, its a number very very close to zero but not exactly zero. Therefore checking &lt;code&gt;empty(json_decode('0E86023'))&lt;/code&gt; would return false.&lt;/p&gt;

&lt;p&gt;This is why this method has been failing for the user and they have not been able to update their information with a value like &lt;code&gt;0E86023&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For a quick fix, I added a simple if statement on top of the method 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="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;is_value_empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&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="nb"&gt;is_numeric&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&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="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt; &lt;span class="o"&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;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&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;$value&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="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;$has_non_empty_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&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;$value&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$row&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="nv"&gt;$has_non_empty_value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$has_non_empty_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;empty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$row&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="o"&gt;!&lt;/span&gt;&lt;span class="nv"&gt;$has_non_empty_value&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;It's interesting that this happened in a case where thousands of other records are been successfully updated but this particular user kept complaining that they could not use the feature.&lt;/p&gt;

&lt;p&gt;So yea, not sure which is weird, &lt;code&gt;json_decode( )&lt;/code&gt; or &lt;code&gt;empty( )&lt;/code&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>bug</category>
    </item>
    <item>
      <title>Use same Dockerfile for Dev &amp; Production</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Thu, 08 Feb 2024 12:02:18 +0000</pubDate>
      <link>https://dev.to/massivebrains/use-same-dockerfile-for-dev-production-1l7f</link>
      <guid>https://dev.to/massivebrains/use-same-dockerfile-for-dev-production-1l7f</guid>
      <description>&lt;p&gt;In many projects that are containerized, especially in cases where development is also done locally with &lt;a href="https://docs.docker.com/compose/"&gt;docker-compose&lt;/a&gt;, teams often have two Dockerfiles, 1 for Development, the other for Production. If you happen to have multiple environments like &lt;code&gt;pre-prod&lt;/code&gt;, &lt;code&gt;staging&lt;/code&gt; and so on, some teams could have different Dockerfiles for these environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/engine/reference/commandline/image_build/#target"&gt;docker build&lt;/a&gt; has a very nice &lt;code&gt;--target&lt;/code&gt; option, that could be used to target a specific &lt;a href="https://docs.docker.com/build/building/multi-stage/"&gt;stage&lt;/a&gt; from the Dockerfile.&lt;/p&gt;

&lt;p&gt;Let's take a very simple example: let's say we are trying to build a simple frontend app with npm, on Development, we start the app with &lt;code&gt;npm run dev&lt;/code&gt; but on production, we need to run &lt;code&gt;npm run generate&lt;/code&gt; and then copy the artefacts to Nginx's html folder to run, we would need to have a Dockerfile as below for Development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "run", "dev"]&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is simply a Dockerfile that starts a frontend app with &lt;code&gt;npm run dev&lt;/code&gt; exposing port 3000.&lt;/p&gt;

&lt;p&gt;However, we typically do not run &lt;code&gt;npm run dev&lt;/code&gt; on production, extra steps are required to generate the static files from the application and then these files are served by &lt;code&gt;nginx&lt;/code&gt; or any other webserver.&lt;/p&gt;

&lt;p&gt;To write the production Dockerfile for this app, we need to build the app and also serve with the desired web server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Multi-Stage builds
&lt;/h3&gt;

&lt;p&gt;Docker &lt;a href="https://docs.docker.com/build/building/multi-stage/"&gt;multi-stage builds&lt;/a&gt; allows us to use multiple &lt;code&gt;FROM&lt;/code&gt; commands in a single Dockerfile, it allows us to selectively copy files from different stages into another.&lt;/p&gt;

&lt;p&gt;For our case, we need a base, dev, build and prod stages, we are going to build our app for production with &lt;code&gt;npm run generate&lt;/code&gt; and we need to serve the built files with nginx. Our production Dockerfile will therefore look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run generate

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:1.25.1-alpine&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/src/dist /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["nginx", "-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the &lt;code&gt;AS build&lt;/code&gt; on the first stage, all commands before any other &lt;code&gt;FROM&lt;/code&gt; is considered a stage on their own.&lt;/p&gt;

&lt;p&gt;After running &lt;code&gt;npm run generate&lt;/code&gt; in the app, it generates files into &lt;code&gt;/usr/src/dist&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the second stage, where we are basing that on &lt;code&gt;nginx&lt;/code&gt;, we simply copy those files from the build stage using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/src/dist /usr/share/nginx/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Updating this Dockerfile to serve both Dev and Production
&lt;/h3&gt;

&lt;p&gt;Now that we have seen multi-stage docker builds in action, we can leverage this by having a &lt;code&gt;base&lt;/code&gt; stage, &lt;code&gt;build&lt;/code&gt; stage and finally a &lt;code&gt;prod&lt;/code&gt; stage.&lt;/p&gt;

&lt;p&gt;To achieve this we update the docker file to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ./package.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;dev&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt;  3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "run", "dev"]&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;nginx:1.25.1-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;prod&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /usr/src/dist /usr/share/nginx/html&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["nginx", "-g", "daemon off;"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are 4 stages in this docker file.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;base&lt;/code&gt; stage
&lt;/h3&gt;

&lt;p&gt;In this stage, we build the base image, copying the files from the project and simply doing &lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;dev&lt;/code&gt; stage
&lt;/h3&gt;

&lt;p&gt;This is the stage that we want to target if we are building this image for &lt;code&gt;dev&lt;/code&gt;. More on how to do this in a bit.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;build&lt;/code&gt; stage
&lt;/h3&gt;

&lt;p&gt;This stage exists so that the &lt;code&gt;prod&lt;/code&gt; stage would be able to copy the generated static files for serving.&lt;/p&gt;

&lt;h3&gt;
  
  
  The &lt;code&gt;prod&lt;/code&gt; stage
&lt;/h3&gt;

&lt;p&gt;This is the stage that we would target when building this image for production.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to target a &lt;code&gt;stage&lt;/code&gt; in Dockerfile
&lt;/h2&gt;

&lt;p&gt;Finally, now that we have a Dockerfile that can serve &lt;code&gt;dev&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt;, to build an image that is specific for dev, we use the &lt;a href="https://docs.docker.com/engine/reference/commandline/image_build/#target"&gt;--target&lt;/a&gt; argument as so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; mutistage:latest &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would make Docker only build up till the &lt;code&gt;dev&lt;/code&gt; stage and nothing else.&lt;/p&gt;

&lt;p&gt;Similarly to build for production we simply do&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; mutistage:latest &lt;span class="nt"&gt;--target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we can maintain the same file for these two environments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>production</category>
      <category>deployment</category>
    </item>
    <item>
      <title>Strive to make it Simple</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Fri, 12 Jan 2024 13:10:00 +0000</pubDate>
      <link>https://dev.to/massivebrains/strive-to-make-it-simple-12k6</link>
      <guid>https://dev.to/massivebrains/strive-to-make-it-simple-12k6</guid>
      <description>&lt;p&gt;When it comes to Software Engineering, simplicity remains the ultimate sophistication. It has become really important that we emphasize the importance of writing really simple Code. I'm not sure if this post will be a rant, or a call to wake you up, but we'll see about that.&lt;/p&gt;

&lt;p&gt;What does it even mean for a piece of software to be implemented with simplicity in mind? What is even considered complexity in an implementation? - Well, I'm not exactly talking about &lt;a href="https://en.wikipedia.org/wiki/Time_complexity"&gt;time complexity&lt;/a&gt; here, nor am I talking about using tools that have the least possible configuration. I'm talking about thinking simple, thinking with the customer in mind, and thinking with an assumption that your future self might not be that smart.&lt;/p&gt;

&lt;p&gt;Simplicity is the art of implementing software with the least possible ambiguity. It is thinking in first principles before anything else. It is attempting to take time to think things through before raising that PR with 6 new npm packages. It is avoiding those confusing smart lines of code, and ultimately writing a maintainable, testable piece of software.&lt;/p&gt;

&lt;p&gt;Understanding the Problem you are trying to solve is the first, non-negotiable step in this journey. More often than not, I've seen engineers attempt to start implementing a ticket without fully understanding the ask, and how that ask affects their customers, their future self, or even the codebase at large. Furthermore, understanding involves narrowing the scope of the ask. Always start small, as small as possible, and walk your way up.&lt;/p&gt;

&lt;p&gt;Writing simple code comes with detachment from the codebase, oftentimes, I have seen engineers attached to their classes, functions, or whatever. It becomes difficult for them to delete code, refactor a method, or even rename a file. If you are one of those people, please understand that your customers don't care.&lt;/p&gt;

&lt;p&gt;The art of simplicity encourages you to actively review previous implementations, taking time to refactor them if you have to, increasing the test coverage in your spare time, or even question your thought process a few months ago. Be bold to remove dead code!&lt;/p&gt;

&lt;p&gt;This is 2024, and we now have AI companions, I challenge you today to embrace this reality, whenever you are trying to solve a technical problem, refactoring a piece of code, or adding extra logic to an existing class, and you have this inner voice saying &lt;em&gt;I'm making this way more complex than it should be&lt;/em&gt; - please take time to ask an AI companion what it would do, ask it to make it simpler, review its options and expose yourself to more possibilities.&lt;/p&gt;

&lt;p&gt;Unfortunately, the technologies, tools, and developer experience products that are most popular today sometimes encourage the most frustrating complexities I can think of. Ask questions, and take time to research alternatives to tools whenever you get a vibe that it's looking way more complex than it should be.&lt;/p&gt;

&lt;p&gt;Simplicity is not just about not confusing yourself today. It's about not confusing yourself tomorrow too. There is no honor in frustrating the next engineer joining your team, and the excuse of time is not acceptable, thinking is the hard part, and in my opinion, clear concise consistent thinking is what makes a solid engineer. Avoid the trap of taking the easy way out.&lt;/p&gt;

&lt;p&gt;I do not want to mention any technology or give any code examples for a good reason. The first step after reading this for anyone interested is to take time to research and review their past work, and the work of others and evaluate how they can simplify it.&lt;/p&gt;

&lt;p&gt;Let me be also clear, simplicity does not imply premature refactoring, enforcing DRY everywhere, or always giving the longest variable or method names. No no, I'm more interested in awakening your thought process and how you take time to think about technical problems first before attempting them.&lt;/p&gt;

&lt;p&gt;For not-so-experienced engineers, please read a lot more code, that is how you find patterns and gain insights into the minds of other experienced engineers.&lt;/p&gt;

&lt;p&gt;I hope that I've left the world simpler than I met it.&lt;/p&gt;

&lt;p&gt;Well, sounds more like a rant, but you get the point.&lt;/p&gt;

</description>
      <category>simplicity</category>
      <category>webdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>MySQL: Searching multiple columns at once without LIKE</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Mon, 23 Jan 2023 13:26:46 +0000</pubDate>
      <link>https://dev.to/massivebrains/mysql-searching-multiple-columns-at-once-without-like-1e17</link>
      <guid>https://dev.to/massivebrains/mysql-searching-multiple-columns-at-once-without-like-1e17</guid>
      <description>&lt;p&gt;Have you ever had reason to search across multiple columns at the same time in MySQL? Maybe while responding to a data-table search from the frontend? - Yea me too.&lt;/p&gt;

&lt;p&gt;You or your ORM probably generate a query like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`addresses`&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`address_line_1`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`address_line_2`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`city`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then when you have reason to add another condition, such that it has to apply to the query separate from the search conditions, you do have to come up with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`addresses`&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;`customer_id`&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;`address_line_1`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`address_line_2`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`city`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt; &lt;span class="k"&gt;LIKE&lt;/span&gt; &lt;span class="nv"&gt;"%NY%"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The more you update the query, adding joins for example and wanting to also include some columns from the join into the searchable fields, the more this query gets complicated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using MySQL LOCATE function
&lt;/h3&gt;

&lt;p&gt;Mysql provides a function called &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_locate" rel="noopener noreferrer"&gt;LOCATE&lt;/a&gt; - This function returns the position of the first occurrence of a given substring. You can checkout other string functions such as &lt;code&gt;POSITION&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;LOCATE&lt;/code&gt; function, we can cleanup the first query to look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`addresses`&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`address_line_1`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`address_line_2`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`city`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;LOCATE&lt;/code&gt; function returns the position of the first occurence of the string, in this case &lt;code&gt;NY&lt;/code&gt;. And it is case-insensitive.&lt;/p&gt;

&lt;p&gt;You are going to say... Well that ain't much of a difference is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Simplyfing with Mysql CONCAT_WS
&lt;/h3&gt;

&lt;p&gt;Now the juicy part 😍 - &lt;code&gt;CONCAT_WS&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The MySQL &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/string-functions.html#function_concat-ws" rel="noopener noreferrer"&gt;CONCAT_WS&lt;/a&gt; is a variant of the &lt;code&gt;CONCAT&lt;/code&gt; function but can accept a separator. So take for example, to return the full address as a column from our &lt;code&gt;addresses&lt;/code&gt; table, we can have a query like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="n"&gt;CONCAT_WS&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="nv"&gt;`address_line_1`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`address_line_2`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`city`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="nv"&gt;`full_address`&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`addresses`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Combining the power of &lt;code&gt;CONCAT_WS&lt;/code&gt; and &lt;code&gt;LOCATE&lt;/code&gt; we can have a relatively easy search without using a &lt;code&gt;LIKE&lt;/code&gt;. Our previous example will then look somewhat like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;`addresses`&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;LOCATE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NY'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CONCAT_WS&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="nv"&gt;`address_line_1`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`address_line_2`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`city`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;`street_name`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this approach, you can add or remove columns that are searchable really easy. Infact you could make it dynamic by accepting searchable columns from your frontend or API.&lt;/p&gt;

&lt;p&gt;On performance, the &lt;code&gt;LOCATE&lt;/code&gt; method is also slightly performant compared to the &lt;code&gt;LIKE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let me know what you think on this approach!&lt;/p&gt;

</description>
      <category>sql</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Deploying a Laravel App on AWS App Runner</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Tue, 17 Jan 2023 10:21:22 +0000</pubDate>
      <link>https://dev.to/massivebrains/deploying-a-laravel-app-on-aws-app-runner-1hmp</link>
      <guid>https://dev.to/massivebrains/deploying-a-laravel-app-on-aws-app-runner-1hmp</guid>
      <description>&lt;p&gt;Deploying a containerized app gets easier everyday as cloud providers release new products. One of such products by AWS is AWS App Runner.&lt;/p&gt;

&lt;p&gt;AWS App Runner is a fully managed container application service that lets you build, deploy, and run containerized web applications and API services without prior infrastructure or container experience.&lt;/p&gt;

&lt;p&gt;Ever want to just deploy an app without the Kubernetes or complex networking overhead? Or have a couple of services to maintain without alot of configuration? - Try AWS App Runner. Read more &lt;a href="https://aws.amazon.com/apprunner" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Following this tutorial
&lt;/h3&gt;

&lt;p&gt;For ease of following this tutorial, I have created a default &lt;code&gt;Laravel&lt;/code&gt; app with all the files referenced in this post. Click &lt;a href="https://github.com/massivebrains/laravel-aws-apprunner" rel="noopener noreferrer"&gt;Here&lt;/a&gt; to view the public github repo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Dockerizing Laravel
&lt;/h3&gt;

&lt;p&gt;Let's start with a Docker file. In this post, I will be using &lt;code&gt;php7.4&lt;/code&gt;. In the root of your Laravel application, create a &lt;code&gt;Dockerfile&lt;/code&gt;. See example &lt;a href="https://github.com/massivebrains/laravel-aws-apprunner/blob/master/Dockerfile" rel="noopener noreferrer"&gt;Here&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Other deployment related files
&lt;/h3&gt;

&lt;p&gt;If you look at the contents of the Dockerfile above, &lt;code&gt;/app/deploy&lt;/code&gt; folder was referenced. This folder contains files for nginx, superiviser and a &lt;code&gt;run&lt;/code&gt; script that would start the laravel app. &lt;a href="https://github.com/massivebrains/laravel-aws-apprunner/tree/master/deploy" rel="noopener noreferrer"&gt;Click here&lt;/a&gt; to copy the contents of this folder to your local Laravel app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build and run your image
&lt;/h3&gt;

&lt;p&gt;To ensure your docker image works locally, run &lt;code&gt;docker build .&lt;/code&gt; to build your image.&lt;/p&gt;

&lt;p&gt;When this builds successfully, you can find your image when you execute &lt;code&gt;docker images&lt;/code&gt; on your cli.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fgo9ys8qcbw3n00w7slj4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fgo9ys8qcbw3n00w7slj4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since the docker image exposes port &lt;code&gt;80&lt;/code&gt;, you can test your image by running:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;
 run -p 8000:80 &amp;lt;image id&amp;gt;

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

&lt;/div&gt;

&lt;p&gt;(Ensure you pass valid database credentials or modify .env.example with reachable database credentials)&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up AWS App Runner
&lt;/h3&gt;

&lt;p&gt;Now let's setup AWS App Runner. First of, AWS App Runner has an automatic deployment option, what this means is that, once our docker repository changes, our app automatically deploys. This is one of the simplicity that makes this product easy to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  AWS Elastic Container Registry
&lt;/h3&gt;

&lt;p&gt;Since we want to automate the entire process, we would be pushing our image automatically to AWS Elastic Container Registry.&lt;/p&gt;

&lt;p&gt;Login to AWS and search for &lt;code&gt;Elastic Container Registry&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F8dxqymwabqops2sy9tim.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F8dxqymwabqops2sy9tim.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don't have an existing repository for your app, go ahead and create one. I will be creating a repository called &lt;code&gt;laravel-aws-app-runner&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F6o0y1e1ravwlsof14l36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F6o0y1e1ravwlsof14l36.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the URI, we would need it later.&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting up Github Actions
&lt;/h4&gt;

&lt;p&gt;For us to automatically build our images and push to ECR from Github we would be using &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's start by adding 2 secrets to our Github repo, &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; and &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;. These two values would be used by the actions to access AWS. Ensure you set your AWS credentials that has access to the ECR you just created.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fzivgicgab2b36ntfr0ma.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzivgicgab2b36ntfr0ma.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your repo, create a Github actions file &lt;code&gt;/.github/production.yml&lt;/code&gt; just like &lt;a href="https://github.com/massivebrains/laravel-aws-apprunner/blob/master/.github/workflows/production.yml" rel="noopener noreferrer"&gt;this&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Take note of the &lt;code&gt;ECR_REPOSITORY&lt;/code&gt; key, update the value to the name of the repository you created in ECR.&lt;/p&gt;

&lt;p&gt;The Github actions tries to checkout the code, login to AWS, build the image and then push it up to the ECR repository.&lt;/p&gt;

&lt;p&gt;Note that it also runs only when there is changes to master, feel free to change this configuration if you want a different branch.&lt;/p&gt;

&lt;p&gt;You may push an empty commit to master to trigger your actions if it has not already been triggered. On your Actions tab, you should see a successful Github Actions run.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhl4lgimo6tz86dmsrthr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhl4lgimo6tz86dmsrthr.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating an AWS App Runner Service
&lt;/h3&gt;

&lt;p&gt;Finally, we have our image pushed to ECR, a Github action to update the image when we merge to master, we can now create a service on App runner that would automatically listen for changes on ECR and update our App.&lt;/p&gt;

&lt;p&gt;On AWS, search for AWS App Runner and click on &lt;code&gt;Create Service&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ff0v9y2nsm05nkcmp3mtn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ff0v9y2nsm05nkcmp3mtn.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If AWS App runner is not available in your preferred region, you may consider using a different region where this product is available.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Source and Deployment&lt;/code&gt; Select &lt;code&gt;Container Registry&lt;/code&gt; and &lt;code&gt;Amazon ECR&lt;/code&gt; as the provider. Choose the correct repository in the list and the default tag is &lt;code&gt;latest&lt;/code&gt; according to our Github actions configuration. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F09m18v01qe342xhnglt6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F09m18v01qe342xhnglt6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, it is actually possible to reference a different docker repository outside of AWS ECR.&lt;/p&gt;

&lt;p&gt;In Deployment settings, select &lt;code&gt;Automatic&lt;/code&gt; - This is very important, with automatic, when our ECR image changes, the service will automatically be deployed.&lt;/p&gt;

&lt;p&gt;If you already have a service role, feel free to choose one of them, other than that you can simply select &lt;code&gt;Create a new service role&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Ftofiig0au84c02jbu4am.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Ftofiig0au84c02jbu4am.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then click on Next.&lt;/p&gt;

&lt;p&gt;On the Service settings, this is where we configure Environment variables, the CPU &amp;amp; RAM of the service, and the port exposed by the Docker image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fk1jtmacrwpm7fpdk96p6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fk1jtmacrwpm7fpdk96p6.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add all the env and values for your service, set the port to &lt;code&gt;80&lt;/code&gt; (Except the Docker file port has been updated). Feel free to change the virtual CPU to 2vCPU, for now i'll leave the default.&lt;/p&gt;

&lt;p&gt;I generally leave the &lt;code&gt;Auto Scaling&lt;/code&gt;, &lt;code&gt;Health Check&lt;/code&gt; &lt;code&gt;Security&lt;/code&gt;, &lt;code&gt;Observability&lt;/code&gt; and &lt;code&gt;Tags&lt;/code&gt; tabs with the default configuration from AWS, but if you are an experienced AWS user and want custom configuration, feel free to modify these tabs to what you want.&lt;/p&gt;

&lt;p&gt;For networking, which is quite important for your service to have access to other resources on your VPC. Your incoming network traffic has to stay as &lt;code&gt;public endpoint&lt;/code&gt; if not your service would not be available on the internet.&lt;/p&gt;

&lt;p&gt;If you would like to change your outgoing access, feel free to do that, but for now, i'll leave both with the defaults.&lt;/p&gt;

&lt;p&gt;One major reason you may change your outgoing access later is because of your database connections as it would most likely be behind a security group in a custom VPC.&lt;/p&gt;

&lt;p&gt;Now that we have all the configurations (mostly all defaults 🙈) We can now go ahead to create &amp;amp; Deploy the service.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F4ne0mnne4e247uk0e2ew.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F4ne0mnne4e247uk0e2ew.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successful deployment, you should have a running service as displayed above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling failed deployment
&lt;/h3&gt;

&lt;p&gt;Just incase your deployment fails, you can view the application logs in Cloudwatch to know what the issue is &lt;br&gt;
&lt;a href="https://media.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%2Fv17ma04vungfj8ta26mw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fv17ma04vungfj8ta26mw.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you see the log and figure out what the issue is from the Image, you can delete the failed service and create a new service.&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic deployments
&lt;/h3&gt;

&lt;p&gt;Now that we have a running service, every time you push to your master branch and Github actions run, the ECR image would be updated and AWS App runner will automatically deploy the app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Domains
&lt;/h3&gt;

&lt;p&gt;Obviously you may want to add Custom domain to your service and not use the default AWS domain. You can do that on the Custom Domains tab. Simply follow the instructions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fyubnapx4cdngs8cvlcl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fyubnapx4cdngs8cvlcl4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Once you get a hang of creating services and setting up Github actions to update the ECR Images, you can pretty much do anything you like such as even having Staging environments.&lt;/p&gt;

&lt;p&gt;AWS App runner is quite straightforward and eliminates setting up your own ServerLess environment from ground up. And since our applications are containerized, you can pretty much switch to another platform in the future if you have too.&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>aws</category>
      <category>docker</category>
      <category>k8s</category>
    </item>
    <item>
      <title>Image or File Uploads in Adonis.js with Cloudinary</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Tue, 06 Aug 2019 13:53:45 +0000</pubDate>
      <link>https://dev.to/massivebrains/image-or-file-uploads-in-adonis-js-with-cloudinary-1b1g</link>
      <guid>https://dev.to/massivebrains/image-or-file-uploads-in-adonis-js-with-cloudinary-1b1g</guid>
      <description>&lt;p&gt;I just started working with adonis JS a little over 2 months now. I recently have to use Cloudinary in my project and i searched for the best way to loosely use it so as to maintain the readable, expressive and approachable structure of Adonis.&lt;/p&gt;

&lt;p&gt;This tutorial assumes you are already familiar with Adonis and Cloudinary. I will explain my approach in steps below. So let's get Started!&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create a new AdonisJS project
&lt;/h2&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adonis new cloudinary-integration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to create a new adonis project. You should get a fresh adonis project (as at the writing of this post, i'm using version &lt;em&gt;4.1&lt;/em&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Setup an upload controller
&lt;/h2&gt;

&lt;p&gt;Create a new HTTP controller by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adonis make:controller Upload &lt;span class="nt"&gt;--type&lt;/span&gt; http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and setup a simple index method as shown below&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UploadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;index &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;It Works &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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UploadController&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And of cause update the &lt;code&gt;/start/routes.js&lt;/code&gt; by adding a new route&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;welcome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//Add this Route&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UploadController.index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Implementing Cloudinary
&lt;/h2&gt;

&lt;p&gt;At this point, if you do not have a cloudinary account, head over to &lt;a href="https://cloudinary.com"&gt;https://cloudinary.com&lt;/a&gt; to create a free account. We would need three major environment variables from cloudinary.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CLOUDINARY_CLOUD_NAME&lt;/li&gt;
&lt;li&gt;CLOUDINARY_API_KEY&lt;/li&gt;
&lt;li&gt;CLOUDINARY_API_SECRET&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Update your &lt;code&gt;.env&lt;/code&gt; file to have these three &lt;code&gt;environment variables&lt;/code&gt;. See Screenshot below on where to get them from your cloudinary console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Mp1am2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/jnoeuznjy43dfw8m6cxy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Mp1am2q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/jnoeuznjy43dfw8m6cxy.jpg" alt="" width="800" height="170"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So your .env file will now look somewhat 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;HOST=127.0.0.1
PORT=3333
NODE_ENV=development
APP_URL=http://${HOST}:${PORT}
CACHE_VIEWS=false
APP_KEY=iBRP92LhBPRKh0rTIcIo2OuyQNbWCY6C
DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=adonis
SESSION_DRIVER=cookie
HASH_DRIVER=bcrypt

#Cloudinary Credentials
CLOUDINARY_CLOUD_NAME=your_cloudinary_cloud_name
CLOUDINARY_API_KEY=your_cloudinary_api_key
CLOUDINARY_API_SECRET=your_cloudinary_api_secret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, Let's pull in the cloudinary JS SDK from npm (or yarn).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i cloudinary &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, create a file &lt;code&gt;/app/Services/Cloudinary.js&lt;/code&gt; with the following code snippet.&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cloudinary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cloudinary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Env&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;

    &lt;span class="na"&gt;cloud_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUDINARY_CLOUD_NAME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUDINARY_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;api_secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CLOUDINARY_API_SECRET&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="na"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;

                &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;uploader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tmpPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

                &lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;secure_url&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

                &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are returning a promise from an &lt;code&gt;async&lt;/code&gt; function called &lt;code&gt;upload&lt;/code&gt; which we would be passing a &lt;code&gt;file&lt;/code&gt; object to. &lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Using the cloudinary Service
&lt;/h2&gt;

&lt;p&gt;Now that we have our Cloudinary service setup. lets create a method in our &lt;code&gt;app/Http/Controllers/UploadController.js&lt;/code&gt; to handle uploads.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;UploadController.js&lt;/code&gt; will now look like this&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;//Import Cloudinary&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Cloudinary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App/Services/Cloudinary&lt;/span&gt;&lt;span class="dl"&gt;'&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;UploadController&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;index &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;It Works &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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;upload &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="c1"&gt;//TODO: Validate. Input.&lt;/span&gt;

        &lt;span class="k"&gt;try&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;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;

                &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;cloudinary_response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Cloudinary&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;image&lt;/span&gt;&lt;span class="dl"&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cloudinary_response&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Please upload an Image.&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="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

            &lt;span class="c1"&gt;//console.log(error)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;UploadController&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;one more thing, lets add a route to our new method. Our routes file will now look like so&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use strict&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;welcome&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;//Add this Route&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UploadController.index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;UploadController.upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 5: Testing from Postman
&lt;/h2&gt;

&lt;p&gt;For the purpose of testing, we do not want to use the CSRF protection for now. So in your &lt;code&gt;/config/shield.js&lt;/code&gt; Update the &lt;code&gt;csrf&lt;/code&gt; key as below so has to exclude the &lt;code&gt;/upload&lt;/code&gt; route&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;csrf: {
    enable: true,
    methods: ['POST', 'PUT', 'DELETE'],
    filterUris: ['/upload'],
    cookieOptions: {
      httpOnly: false,
      sameSite: true,
      path: '/',
      maxAge: 7200
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now to test our upload route and be sure our implementation is working as expected. Try uploading a file from postman as shown below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9XLKINYu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/oqctjuony55mlanhrgl0.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9XLKINYu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/oqctjuony55mlanhrgl0.jpg" alt="" width="800" height="487"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should be able to see your newly uploaded file from your cloudinary media library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KgY8wjKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/6556g3rllzaknc5zj69y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KgY8wjKN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://thepracticaldev.s3.amazonaws.com/i/6556g3rllzaknc5zj69y.jpg" alt="" width="800" height="258"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's all folks!&lt;/p&gt;

</description>
      <category>image</category>
      <category>adonisjs</category>
      <category>cloudinary</category>
    </item>
    <item>
      <title>Deploying Node/Express app on a Windows Server</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Wed, 03 Jul 2019 14:14:10 +0000</pubDate>
      <link>https://dev.to/massivebrains/deploying-node-express-app-on-a-windows-server-2l5c</link>
      <guid>https://dev.to/massivebrains/deploying-node-express-app-on-a-windows-server-2l5c</guid>
      <description>&lt;p&gt;I had this small side project I worked on for a client over a weekend, it was a simple express API. &lt;br&gt;
Everything worked well and good until it was time to deploy! This was my conversation with the client..&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Me&lt;/em&gt;: Cool so the app is ready, can you send me your staging server details so i can deploy for you?&lt;br&gt;
&lt;em&gt;Client&lt;/em&gt;: Yea cool, i will send you an RDP credentials to our Windows VM&lt;br&gt;
&lt;em&gt;Me&lt;/em&gt;: Wait what? &lt;a href="https://media.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%2F48zglc17rit5u7am3s5m.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F48zglc17rit5u7am3s5m.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ok jokes apart, lets get straight into it!&lt;/p&gt;

&lt;p&gt;Before we continue, you should have a basic knowledge of Setting up a simple &lt;a href="https://expressjs.com/" rel="noopener noreferrer"&gt;Express App&lt;/a&gt; and using &lt;a href="https://nodemon.io/" rel="noopener noreferrer"&gt;Nodemon&lt;/a&gt; or  any other Node Process manager.&lt;/p&gt;

&lt;p&gt;To speed things up, i have setup a simple express app with a single endpoint for this demo, please note that the target is not necessarily an introduction to Express but how to deploy an Express based app on Windows.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/massivebrains" rel="noopener noreferrer"&gt;
        massivebrains
      &lt;/a&gt; / &lt;a href="https://github.com/massivebrains/express-demo" rel="noopener noreferrer"&gt;
        express-demo
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      An Express Demo App
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;express-demo&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;An Express Demo App&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/massivebrains/express-demo" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;You can clone the repo to follow along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the express app on the server
&lt;/h2&gt;

&lt;p&gt;If you are using the sample app that was cloned, run &lt;code&gt;yarn&lt;/code&gt; and then &lt;code&gt;yarn start&lt;/code&gt; . The app should now start with &lt;code&gt;nodemon&lt;/code&gt;. Assuming you have not changed the default port, head over to your browser at &lt;a href="http://localhost:3000" rel="noopener noreferrer"&gt;http://localhost:3000&lt;/a&gt; . you should see the sample json response as below&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;status:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;data:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Api Works"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up a proxy with IIS
&lt;/h2&gt;

&lt;p&gt;Now the app is running locally but not available outside the server. What we want is for the public to be able to reach the app at &lt;code&gt;http://yourdomain.com/app&lt;/code&gt; where &lt;code&gt;http://yourdomain.com&lt;/code&gt; is our domain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;p&gt;Search and open Internet Information Services (IIS)&lt;br&gt;
&lt;a href="https://media.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%2Fzj0n89vtnun72cr3qb9q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fzj0n89vtnun72cr3qb9q.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2
&lt;/h3&gt;

&lt;p&gt;Expand Sites -&amp;gt; Default Web Site&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fe1j17tyjgyud4nq07mtz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fe1j17tyjgyud4nq07mtz.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Right click on &lt;em&gt;Default Web Site&lt;/em&gt; and select &lt;em&gt;Add Application&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fa3va0n3cpx0rmoverzt1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fa3va0n3cpx0rmoverzt1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a URL rewrite
&lt;/h3&gt;

&lt;p&gt;Make sure the newly created app is selected under the &lt;em&gt;Default Web Site&lt;/em&gt;, click on &lt;em&gt;URL Rewrite&lt;/em&gt; from the IIS dashboard on the right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fcfjn5fwcvh1o3xod5s1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fcfjn5fwcvh1o3xod5s1j.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the right, click on &lt;em&gt;Add Rule(s)&lt;/em&gt; and then select &lt;em&gt;Reverse Proxy&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2Fhlpbyf73xhb1olxqo2ts.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2Fhlpbyf73xhb1olxqo2ts.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the inbound rules dialogue box, enter &lt;code&gt;localhost:3000&lt;/code&gt; as illustrated below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.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%2F87dbfasjauq0mwfok0cb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.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%2F87dbfasjauq0mwfok0cb.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you changed the port number where the express app is currently running, make sure you use &lt;code&gt;localhost:{port_number}&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Click on &lt;em&gt;OK&lt;/em&gt; after this.&lt;/p&gt;

&lt;p&gt;Now head over to a browser (outside your server) and try to access &lt;em&gt;&lt;a href="http://yourdomain.com/api" rel="noopener noreferrer"&gt;http://yourdomain.com/api&lt;/a&gt;&lt;/em&gt; (where &lt;em&gt;&lt;a href="http://yourdomain.com" rel="noopener noreferrer"&gt;http://yourdomain.com&lt;/a&gt;&lt;/em&gt;) is your actual domain name.&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>iis</category>
      <category>windows</category>
    </item>
    <item>
      <title>Single Method Controllers in Laravel</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Tue, 02 Jul 2019 07:39:16 +0000</pubDate>
      <link>https://dev.to/massivebrains/single-method-controllers-in-laravel-4gf6</link>
      <guid>https://dev.to/massivebrains/single-method-controllers-in-laravel-4gf6</guid>
      <description>&lt;p&gt;We all agree that methods and function should do one thing only. We call this &lt;em&gt;Single Responsibility Principle&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;However, the fact that methods should follow SRP does not imply that we should have a controller housing many (almost) independent methods which would result in a very unstructured business logic.&lt;/p&gt;

&lt;p&gt;Having a single method controller is a fantastic way of upholding the &lt;em&gt;Single Responsibility Principle&lt;/em&gt;. For example, take a look at the controller below&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;App\Http\Controllers\Api&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\Http\Request&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;App\Http\Controllers\Controller&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;App\Plan&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;PlansController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;index&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Logic to Get All Plans&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;create&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Logic to create new Plan&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;inviteUser&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Logic to invite user to plan&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;The first thought that would come to mind is that the &lt;code&gt;inviteUser&lt;/code&gt; method does not belong to this controller. We should have something like &lt;code&gt;InviteUserController&lt;/code&gt;. And that is absolutely what we should do.&lt;/p&gt;

&lt;p&gt;From the name of this controller, it is expected to do one thing only - Invite a user to a specific plan. &lt;/p&gt;

&lt;p&gt;So we can simply have something 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="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Http\Controllers\Api&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\Http\Request&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;App\Http\Controllers\Controller&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;InviteUserController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;inviteUser&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Logic to invite user to plan&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 we should be done right? - Well how about if this could be done better? - Introducing Magic Method &lt;code&gt;__invoke&lt;/code&gt; :)&lt;/p&gt;

&lt;p&gt;PHP has several Magic methods. Magic methods are named with two underscores at the start, which get called automatically when a particular event happens.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;__invoke()&lt;/code&gt; method gets called when the object is called as a function. When you declare it, you say which arguments it should expect. Here's a trivially simple example:&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="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Human&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;__invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Sophisticated creature"&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;We can instantiate a Human object, and then just use it like a function:&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;$victor&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;Human&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$victor&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Sophisticated creature&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this understanding, we can simply rename the &lt;code&gt;inviteUser&lt;/code&gt; method of the &lt;code&gt;InviteUserController&lt;/code&gt; to &lt;code&gt;__invoke&lt;/code&gt; as seen below&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;App\Http\Controllers\Api&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\Http\Request&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;App\Http\Controllers\Controller&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;InviteUserController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Controller&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;__invoke&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="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;//Logic to invite user to plan&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 routes file we would no more use the string literal convention to map a route to this controller instead we add the class 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="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Http\Controllers\Api&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;'/invite'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;InviteUserController&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me know what you think about single method controllers!&lt;/p&gt;

&lt;p&gt;Credit: &lt;a href="https://lornajane.net/posts/2012/phps-magic-__invoke-method-and-the-callable-typehint"&gt;lornajane&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;PS: This is my first blog post on Dev.to&lt;/em&gt;&lt;/p&gt;

</description>
      <category>laravel</category>
      <category>php</category>
    </item>
    <item>
      <title>Hi, I'm Massive brains</title>
      <dc:creator>Segun Olaiya</dc:creator>
      <pubDate>Wed, 18 Jan 2017 22:05:27 +0000</pubDate>
      <link>https://dev.to/massivebrains/hi-im-massive--brains</link>
      <guid>https://dev.to/massivebrains/hi-im-massive--brains</guid>
      <description>&lt;p&gt;I have been coding for [3] years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/massivebrains00" rel="noopener noreferrer"&gt;@massivebrains00&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in [lagos].&lt;/p&gt;

&lt;p&gt;I work for [company]&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: [php].&lt;/p&gt;

&lt;p&gt;I am currently learning more about [javascript].&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
