<?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: Emmanuel Awotunde</title>
    <description>The latest articles on DEV Community by Emmanuel Awotunde (@olaoluwa98).</description>
    <link>https://dev.to/olaoluwa98</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%2F31568%2F507a4b85-4ec7-4e13-9434-3cf47a482b13.jpg</url>
      <title>DEV Community: Emmanuel Awotunde</title>
      <link>https://dev.to/olaoluwa98</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olaoluwa98"/>
    <language>en</language>
    <item>
      <title>Building More Resilient Backend Infrastructures</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Thu, 29 Oct 2020 05:48:47 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/building-more-resilient-backend-infrastructure-54gl</link>
      <guid>https://dev.to/olaoluwa98/building-more-resilient-backend-infrastructure-54gl</guid>
      <description>&lt;p&gt;When building for the web, the backend infrastructure is usually the part that needs the most security and resilience. Over the years, the web has grown very large. There are billions of people surfing the web today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some perspective
&lt;/h2&gt;

&lt;p&gt;To put it in perspective, Facebook has over 2.7 billion monthly active users as of the second quarter of 2020 (1), Instagram has over 1 billion monthly active users (2), Twitter has over 330 million (3). Compare this to the current population of the world which is about 7.8 billion as of October 2020 (4).&lt;/p&gt;

&lt;p&gt;So when building software for the web, you need to put this into consideration. Compared to the late '90s and early 2000s, whatever we are building today has the potential of being used by billions of people. Millions of people could be using our software simultaneously. To ensure we are building what can serve this high population, a lot of things have to be considered when building the infrastructure of the backend. No doubt, the frontend and other parts of a software matter just as much but in this article, my focus is on the backend.&lt;/p&gt;

&lt;p&gt;I have spent more than 2 years writing a backend for software that serve tens of thousands of users, I have experienced a lot of challenges and I can only imagine the challenges I'd face when the users of those software grow into hundreds of thousands, millions and billions. One thing I have realized is that in software, experience teaches you a lot of things you would not learn from training or tutorials. I thought to compile challenges that you can face in building for a growing population of users.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I wrote this
&lt;/h2&gt;

&lt;p&gt;I got this idea while talking with one of my friends, Nicholas, an engineer at Paystack. At that time, I was confronting a challenge I encountered with an implementation I wrote for a particular part of the codebase I manage at my company. I spoke with him and he was able to profer a viable solution.&lt;/p&gt;

&lt;p&gt;Whenever I encounter a major bug and it's taking more than 10 minutes or more to figure out, I decide to stop using the conventional ways of fixing bugs. If a bug is taking me too long to fix, it most likely means that I don't have enough knowledge in the domain of that that bug is showing up. For example, if I encounter a bug that has to do with reading files in Node.js and it's taking me more than 10 minutes to figure out then I need to back out from attempting to fix the bug. What I do is read a few articles or videos of working with files in Node.js. I also reach out to people who I know are experts in the domain. I could figure out what's wrong from this or just having the knowledge will streamline my search for how to fix the bug. This has long term benefits. This is just by the way.&lt;/p&gt;

&lt;p&gt;Back to the point of this article. How do we build a resilient backend? This isn't dependent on the programming languages or frameworks you use. Writing code is an art, the more creative the artist is the better the work of art. In building a resilient backend, there a number of things I have found out from experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whatever can go wrong will go wrong
&lt;/h2&gt;

&lt;p&gt;This is a very relevant idea to have when building backend infrastructures. You should note things that as they come to your mind and ensure to come back to them. While coding, you may have thoughts that some implementation you wrote may be problematic or may break in certain situations. It's better to either stop and consider all the ways things can go wrong and handle them properly or comment in the code that you have some concerns so you or anyone who looks through the code could attempt to fix it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Single point of failure
&lt;/h2&gt;

&lt;p&gt;The larger your backend infrastructure, the more attention you need to give to it. You need to constantly monitor all the moving parts and ensure they are smooth. If you notice unusual traffic in certain areas, you should note them and attend to them. You should look out for bottlenecks and single points of failure. A single point of failure is a part of your infrastructure that if it fails, the whole backend infrastructure will not be able to function. You should either reduce as many single points of failure as possible or work very hard to secure and ensure they are very reliable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automation
&lt;/h2&gt;

&lt;p&gt;As your backend infrastructure grows bigger, you need to automate a lot of things you previously did manually. Some examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;running database migration&lt;/li&gt;
&lt;li&gt;running builds&lt;/li&gt;
&lt;li&gt;code linting and formatting&lt;/li&gt;
&lt;li&gt;backups&lt;/li&gt;
&lt;li&gt;deployment&lt;/li&gt;
&lt;li&gt;and many more&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoring
&lt;/h2&gt;

&lt;p&gt;Monitoring how well your backend is performing will give you insights on how to improve it. You should use robust monitoring tools depending on how large your backend is. Tools like &lt;a href="https://prometheus.io/"&gt;Prometheus&lt;/a&gt;, &lt;a href="https://grafana.com"&gt;Grafana&lt;/a&gt;, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security
&lt;/h2&gt;

&lt;p&gt;Take security very seriously on the first day. There are many areas to consider security&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code - perform validation before processing data, add lots of checks to prevent malicious activities. You should also implement rate limiters to prevent DDoS attacks&lt;/li&gt;
&lt;li&gt;Secrets - you should protect all your secret keys&lt;/li&gt;
&lt;li&gt;Server &amp;amp; cluster - ensure you implement things like firewalls and other server related security checks&lt;/li&gt;
&lt;li&gt;Load balancer - apply the same security checks for your load balancers&lt;/li&gt;
&lt;li&gt;Database - ensure no one else can access your database. It's advisable to only allow incoming request from your servers alone to prevent brute force attacks&lt;/li&gt;
&lt;li&gt;Domain - when purchasing a domain, some domain providers offer extra security for your domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should consult experts in the security domain to help you tighten your loose ends.&lt;/p&gt;

&lt;h2&gt;
  
  
  Routine checks
&lt;/h2&gt;

&lt;p&gt;As an extension of security, you should perform routine checks on your servers to ensure everything is stable. You should have a schedule for this, it could be daily, weekly, monthly, quarterly or anyone that works for you and your team. This could help you to catch errors on time. It keeps you informed and you can know how frequently certain errors show up and how you can prevent them. You can also write different scripts to do these checks so you can even plug it into a cron job and it notifies you when it finds anything fishy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code quality
&lt;/h2&gt;

&lt;p&gt;Your codebase is being used by two sets of people. The customers it's serving and the developers that are working on it. A code that works is good for customers, a code that's readable is good for developers. Your code quality will help you iterate faster and build new features faster. You'd be able to have more developers work on the codebase because it will be easier to read and understand.&lt;/p&gt;

&lt;p&gt;A lot of things go into ensuring high code quality. Things like documenting, commenting where needed, having good workflows (such as git flow), having a checklist before allowing code merge into the main branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated tests
&lt;/h2&gt;

&lt;p&gt;You should write tests to cover for as many scenarios as possible. This will make you more confident in your code and reduce the number of manual tests you have to carry out. You should also add a test step to your continuous integration so no feature is shipped without passing its tests. This is extremely useful when refactoring implementations, you run the test before refactoring, you run the test after refactoring. This will help you know if you broke the code. Of course, you may not be able to write an automated test for everything, there are times you have to test manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common database tricks
&lt;/h2&gt;

&lt;p&gt;I have used SQL databases more than I have used NoSQL databases. Most of the common tricks in this list are for SQL databases.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transactions - there are certain flows in your application that needs to run a number of database writes that must all happen in a sequence and if one fails, all should fail. You can use database transactions to achieve this&lt;/li&gt;
&lt;li&gt;Racing conditions - a racing condition occurs when two database queries try to access and update the same row simultaneously. This causes computational inconsistencies. You can fix this problem using specific select queries. You can check this &lt;a href="https://stackoverflow.com/questions/2364273/how-to-make-sure-there-is-no-race-condition-in-mysql-database-when-incrementing"&gt;stackoverflow question&lt;/a&gt; to learn more.&lt;/li&gt;
&lt;li&gt;Pagination - when fetching data from a user-generated table, it's best to paginate because attempting to fetch all at once will be problematic as the table grows very large.&lt;/li&gt;
&lt;li&gt;Others - there are a lot more issues to consider when using databases. It's better to consider and implement them from day one.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Timezone issues
&lt;/h2&gt;

&lt;p&gt;I like the following articles on working with timezones. You should check them out.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/corykeane/3-simple-rules-for-effectively-handling-dates-and-timezones-1pe0"&gt;3 simple rules for effectively handling dates and timezones by Cory Keane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@toastui/handling-time-zone-in-javascript-547e67aa842d"&gt;Handling Time Zone in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Failover, fallbacks, retries and rollbacks
&lt;/h2&gt;

&lt;p&gt;To keep backend servers operational all the time, you need to implement failover in the case of a service outage. You should have a backup plan for when your primary servers crash or experience outage.&lt;/p&gt;

&lt;p&gt;Fallbacks are similar too but this can be applied to the backend code and third-party integrations e.g payment. If your application depends on a third party service then you should handle cases when the third party service will be offline gracefully and provide a form of fallback action that should occur instead.&lt;/p&gt;

&lt;p&gt;Having retries is also another good way of ensuring reliability. For services that need to be available all the time, if there's a slight issue with the service then the connection should be retried a number of times and timeout to notify you that there's a serious issue with the service. If it's a less important service and retries are an expensive operation then you can implement exponential back off. Exponential backoff is an algorithm that uses feedback to multiplicatively decrease the rate of some process, in order to gradually find an acceptable rate. You can check out this &lt;a href="https://cloud.google.com/iot/docs/how-tos/exponential-backoff"&gt;article on Google Cloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rollbacks, a good deployment process should include a rollback option. When you mistakenly ship a bug into production, instead of attempting to quickly fix the bug and redeploying, you should be able to rollback your deployment to the older version.&lt;/p&gt;

&lt;h2&gt;
  
  
  Queues
&lt;/h2&gt;

&lt;p&gt;When handling requests from users, there are some computations/processes that may take very long and the request may timeout. Such computations/processes can be handled by Queues. Queues can solve many different problems in an elegant way, from smoothing out processing peaks to creating robust communication channels between microservices or offloading heavy work from one server to many smaller workers, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributed systems
&lt;/h2&gt;

&lt;p&gt;This article doesn't cover design patterns for distributed systems. You can read about them in these links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dzone.com/articles/performance-patterns-in-microservices-based-integr-1"&gt;Performance Patterns in Microservices-Based Integrations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.slideshare.net/KristofferErlandsson/building-fault-tolerant-microservices"&gt;Building Fault Tolerant Microservices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.redhat.com/blog/2017/05/16/it-takes-more-than-a-circuit-breaker-to-create-a-resilient-application"&gt;It takes more than a Circuit Breaker to create a resilient application&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Keeping up to date
&lt;/h2&gt;

&lt;p&gt;I sometimes read about how companies managing large scale applications solve difficult problems. This helps me foresee some problems or challenges I may face in the future and learn about them before time. Two blogs come to mind.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://eng.uber.com/"&gt;Uber Engineering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slack.engineering/"&gt;Slack Engineering&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that you don't have to solve the problems they solve the same way or take their own solution as final, you should just learn from their solution and that can help you think of better solutions. You should also know how large their application is and compare that to the problem before you start assuming your own application will face the same problems soon.&lt;/p&gt;

&lt;p&gt;There are definitely more challenges I haven't faced yet but these are very common ones you will face when building for a growing population of users. Remember that most challenges will be specific for your situation so you should seek to understand your situation well and apply the right solution to it.&lt;/p&gt;

&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;p&gt;(1) &lt;a href="https://www.statista.com/statistics/264810/number-of-monthly-active-facebook-users-worldwide"&gt;https://www.statista.com/statistics/264810/number-of-monthly-active-facebook-users-worldwide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(2) &lt;a href="https://backlinko.com/instagram-users"&gt;https://backlinko.com/instagram-users&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(3) &lt;a href="https://ng.oberlo.com/blog/twitter-statistics#:~:text=Summary%3A%20Twitter%20Statistics,-Here's%20a%20summary&amp;amp;text=There%20are%20330%20million%20monthly,female%20and%2066%20percent%20male."&gt;https://ng.oberlo.com/blog/twitter-statistics&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(4) &lt;a href="https://www.worldometers.info/world-population"&gt;https://www.worldometers.info/world-population&lt;/a&gt;&lt;/p&gt;

</description>
      <category>backend</category>
      <category>infrastructure</category>
      <category>architecture</category>
    </item>
    <item>
      <title>My Experience With Rebuilding a Product from Ground Up</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Tue, 20 Oct 2020 06:33:14 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/my-experience-with-rebuilding-a-product-from-ground-up-394f</link>
      <guid>https://dev.to/olaoluwa98/my-experience-with-rebuilding-a-product-from-ground-up-394f</guid>
      <description>&lt;p&gt;I joined my present company (&lt;a href="https://pettysave.com"&gt;Pettysave&lt;/a&gt;) mid-2019 after concluding my undergraduate studies. In my first few weeks, I didn't feel like I was in a tech company. The business product was initially built by an outsourcing agency. In my opinion, they didn't do a good job with the product. Of course, I wasn't present during the process of developing the product so I did not know how they got there. One thing was sure, the product was very problematic and needed an upgrade.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems With Outsourcing
&lt;/h2&gt;

&lt;p&gt;Outsourcing the development of your business product is not bad but before doing it, you should definitely know the pros and cons. It is usually an easy and cheap short-term option.&lt;br&gt;
Apart from the problems I personally experienced with the outsourcing company that built the initial version of Pettysave, I also did a little research and found that it's an often discussed issue globally. Instead of listing the problems, you can just read these really good articles. They explain what I'd have written here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.blog/2019/10/01/pitfalls-avoid-outsourcing-software-development"&gt;Five Pitfalls To Avoid When Outsourcing Software Development - Stackoverflow Blog article by Rahul Varshneya&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@danielalcanja/the-new-era-of-outsourcing-software-development-c5c4099342b3"&gt;The Challenges of Outsource Software Development - Medium post by Daniel Alcanja&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.n-ix.com/how-to-solve-problems-of-it-outsourcing"&gt;How to solve 13 harsh problems of outsourcing - N-ix article by Nadia Serheichuk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Initial Worries
&lt;/h2&gt;

&lt;p&gt;When I joined the team, I had only one engineering teammate. My teammate was a frontend engineer while I was a backend engineer. I remember being very concerned with the product and how we could make it better. Pettysave management hired two of us to take over the product from the outsourcing agency. After several discussions with the outsourcing agency and my teammate, we decided we'd rebuild the product and rewrite the entire codebase.&lt;/p&gt;

&lt;p&gt;The initial version of the Pettysave product was built with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ASP.NET (Onion Architecture) - For the website&lt;/li&gt;
&lt;li&gt;Microsoft SQL Server - Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I had no experience with the .NET stack and generally did not like it anyway. It was a no-brainer for me to start learning what I didn't like. I spent a week or more doing research on which stack we were going to use. I read a lot of articles and talked to friends.&lt;br&gt;
After much research, I had two options for the backend stack: Node.js or Python. The frontend stack was decided on time: Vue.js. After looking at my current skill-set, I decided to go with Node.js.&lt;br&gt;
This eventually became the new stack for Pettysave:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vue.js - Frontend&lt;/li&gt;
&lt;li&gt;Node.js (Adonis.js) - Backend&lt;/li&gt;
&lt;li&gt;MySQL - Database&lt;/li&gt;
&lt;li&gt;Redis - In-memory Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After deciding the new stack, the next piece of the puzzle was how we were going to migrate the database. This is a very important step that should be done early in the process because it determines if you can move forward or not. We were migrating from Microsoft SQL to MySQL. Luckily for us, they are fairly similar but they have lots of differences regardless. I spent time researching the best approach to solve this. The structure of the old database wasn't the best so I had to make modifications to make it more normalized and to track more information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migrating the database
&lt;/h2&gt;

&lt;p&gt;Because this step was very important, I had to be very careful. I had a few concerns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing the structure of the database without destroying old data&lt;/li&gt;
&lt;li&gt;Migrating the passwords of users i.e rehashing to fit new hashing algorithm in version 2&lt;/li&gt;
&lt;li&gt;Generating new data to fit new database structure i.e populating new tables or columns created in version 2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I eventually found a tool that could migrate a database in MSSQL to MySQL: MySQL Workbench. You can read this article to know how it works: &lt;a href="https://severalnines.com/database-blog/how-migrate-mssql-mysql"&gt;How to Migrate from MSSQL to MySQL by Sebastian Insausti&lt;/a&gt;. After several trials, I was able to convert the database to MySQL. The next step was to transform the MySQL database into the new data structure for version 2.&lt;/p&gt;

&lt;p&gt;This proved to be a very hard task because I had to write a script for it and test it several times. This took weeks, no kidding. I didn't spend the whole day working only on the script, I was still writing the backend for version 2 alongside. I got frustrated a lot during this process and even scared sometimes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Writing the Backend
&lt;/h2&gt;

&lt;p&gt;As I said earlier, I had to rewrite the whole backend infrastructure from the ground up. It was fairly easy because I learnt from the current version of the product and improved on it. I used &lt;a href="https://adonisjs.com/"&gt;Adonis.js&lt;/a&gt;, a Node.js framework. Adonis.js is a really simple framework to use, it was modelled after &lt;a href="https://laravel.com/"&gt;Laravel&lt;/a&gt;. It had most of the things I needed to write a savings &amp;amp; investment backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Routing&lt;/li&gt;
&lt;li&gt;Database ORM&lt;/li&gt;
&lt;li&gt;Middleware&lt;/li&gt;
&lt;li&gt;Mailing&lt;/li&gt;
&lt;li&gt;Validator&lt;/li&gt;
&lt;li&gt;Authentication&lt;/li&gt;
&lt;li&gt;Encryption &amp;amp; Hashing&lt;/li&gt;
&lt;li&gt;File Upload&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Events&lt;/li&gt;
&lt;li&gt;Testing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I enjoyed most of the time I spent writing the backend code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handover
&lt;/h2&gt;

&lt;p&gt;When I started working on the backend, Pettysave management had requested for the codebase of version 1 from the outsourcing agency. We got the codebase weeks later. So I was able to extract more information from the code. I saw lots of mistakes they made and thought of ways to correct them in version 2.&lt;/p&gt;

&lt;p&gt;Apart from the codebase, the outsourcing agency had our domain name, hosting, database and some API keys. So we started the process of retrieving all these. The hardest one to retrieve was the domain name because it was bought in their name so they had to do domain transfer, it took a while to do this. We didn't need the hosting because we weren't going to deploy into a Windows environment, we discarded all old API keys they had access to prevent any funny thing that may occur in the future.&lt;/p&gt;

&lt;p&gt;Once we got everything, we were more confident about the launch and to continue the maintenance of the platform.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test &amp;amp; Launch
&lt;/h2&gt;

&lt;p&gt;After about 3 months of working on version 2 with my team members, we were set to launch. Others were set to launch, I wasn't. I was yet to finish the database migration script. I focused more on the script and spent much time on SQL. I learnt so much about SQL in that period. When I completed the script and tested it, we were now ready for launch. We had previously shifted the launch date like 4 times. We eventually settled on January 17th 2020. I had deployed a test version of the product so we could be testing internally. That had been going for weeks, this process is very important. It's easy to know if a product was tested before launch. A tested product is more usable than a non-tested one. It's that simple because, during the test, people simulate how users will use it and give feedback on how to improve the usability of the product.&lt;/p&gt;

&lt;p&gt;On the launch day, of course, I was still making a lot of edits to the backend and working on the deployment. I had chosen AWS for hosting. So I made use of Docker and deployed to AWS Elastic Container Service (ECS). I wrote an &lt;a href="https://codechauffeur.com/easy-deployment-setup-with-bitbucket-and-aws-ecs/"&gt;article about deploying to ECS&lt;/a&gt;. Version 2 of Pettysave went live at about 11 am. Poof! that was it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launching Mobile Apps
&lt;/h2&gt;

&lt;p&gt;Version 2 of the website was at &lt;a href="https://app.pettysave.com"&gt;app.pettysave.com&lt;/a&gt;. We used Cordova to bundle the web application into a mobile app. We submitted the apk for the Android version to Play Store later that day. Releasing on iOS was a longer process. We had to first apply to the Developer account of App Store to get approval. That took about a week before we were able to submit the app on App Store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Problems After Launch
&lt;/h2&gt;

&lt;p&gt;Once we launched, we initially experienced a lot of problems with the servers. I had provisioned a very small EC2 (Elastic Compute Cloud) instance so the server kept crashing several times day. I had to stay up all night to ensure it was stable.&lt;/p&gt;

&lt;p&gt;Due to the changes in the data structures on the database, there was some information I had to generate. Some customers complained that their data wasn't consistent with the old version, I had to do checks to ensure they were all corrected.&lt;/p&gt;

&lt;p&gt;Alongside the API server, we had a task runner (cron job) that was responsible for debiting customers when it's their turn to save. Initially, I had written a simple loop to get all the debit cards and made API calls to our payment processor to charge the card. This was a very bad idea because one error stopped the whole loop and that was occurring every day after launch. I had to do some research and speak with my friends on how to solve this, I eventually used a queuing system to solve it (I'd write an article about later).&lt;/p&gt;

&lt;p&gt;The deployment was manual at launch, I had built the docker images on my PC and push to AWS  ECS (Elastic Container Registry). After a week or more, I set up continuous delivery on Bitbucket so that whenever the master branch was updated, a build is triggered and deployed without any manual process. This saved me a lot of time and headache. I explained how I did this in &lt;a href="https://codechauffeur.com/easy-deployment-setup-with-bitbucket-and-aws-ecs/"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  After Launch
&lt;/h2&gt;

&lt;p&gt;One thing was clear once we launched, we had to be ready to answer our customers' questions on complaints. We were ready, we had installed an instant chat service directly on the app. We received lots of complaints about the new changes. Many customers were happy with them, some weren't but it was a generally positive response. We also set up our support mail [&lt;a href="mailto:support@pettysave.com"&gt;support@pettysave.com&lt;/a&gt;] which I handled. I handled the complaints from customers for several months. This made me have a deeper understanding of what to build and what's important to customers.&lt;/p&gt;

&lt;p&gt;It's been 9 months since then and the progress we've made has been fantastic. We acquired more users in the first 3 months of version 2 than the first one year of version 1. That's more than 100% increase in user growth. Revenue also went up and is still going up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lessons I Learnt
&lt;/h2&gt;

&lt;p&gt;I really loved the experience of working a product from the ground up. The joy of building something that adds value to people is really great. Rebuilding a product gives you flexibility and allows you to correct old mistakes and make new and better approaches to solving old problems. The problem the product was solving didn't change, the product did.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You cannot optimize the code you haven't written - until you write the code before you can optimize it&lt;/li&gt;
&lt;li&gt;Focus on the most important aspects of the product - there are many other aspects that are not so important and could distract you&lt;/li&gt;
&lt;li&gt;Listen to your customers, your customers tell you their problem - it's your job to figure out the solutions to their problems&lt;/li&gt;
&lt;li&gt;Prepare for failure - when building a product, you should know that things go wrong so be prepared for this&lt;/li&gt;
&lt;li&gt;Iterate fast - receive feedback from customers and use it to build and iterate new features&lt;/li&gt;
&lt;li&gt;Measure progress and success - before improving a product, you should have success metrics you'd use to determine if your new version is successful&lt;/li&gt;
&lt;li&gt;Chill - there will always be work to do, don't overwork yourself, have a plan and include rest in your plan&lt;/li&gt;
&lt;li&gt;Celebrate - celebrate your wins, after releasing new features you should celebrate as it grants you the reward for your work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pettysave is an online savings and investment platform that helps people achieve their financial goals, you can sign up with my referral link to receive a &lt;strong&gt;NGN250&lt;/strong&gt; bonus when you start saving. Sign up here: &lt;a href="https://app.pettysave.com/s/EMMA16522"&gt;app.pettysave.com/s/EMMA16522&lt;/a&gt;&lt;/p&gt;

</description>
      <category>product</category>
      <category>refactoring</category>
      <category>startup</category>
    </item>
    <item>
      <title>A Simple Road Map to Learn New Frameworks</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Mon, 27 Jul 2020 23:58:57 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/a-simple-road-map-to-learn-new-frameworks-eb2</link>
      <guid>https://dev.to/olaoluwa98/a-simple-road-map-to-learn-new-frameworks-eb2</guid>
      <description>&lt;p&gt;It's 2020, there are lots of things to learn as a software developer. Your ability to learn fast sets you apart.&lt;/p&gt;

&lt;p&gt;One of the best things about modern software development is the availability of free tools and frameworks. For example, as a frontend developer there's a lot of frontend frameworks you can use: React, Vue, Angular, Emberjs, Backbonejs, and many more.&lt;br&gt;
This could be challenging because you have to select what to use. A developer in 2020 would have used at least 2 frameworks one time or another.&lt;/p&gt;

&lt;p&gt;Picking up a new framework is good for the learning experience and expanding your perspective. It doesn't really matter which framework it is. I see it as starting a new adventure. I have used a lot of frameworks over time. In this article, I will explain some methods I used to learn fast and also talk about some nuances that surround the frameworks' ecosystems.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Getting the Overview&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A simple overview of the framework helps create a foundation or a sort of guide. Most frameworks have a website and give a short explanation of the framework. A good explanation will include a particular problem the framework aims to solve. Knowing this will help you see the point of using the framework.&lt;/p&gt;

&lt;p&gt;An example is &lt;a href="//reactjs.org"&gt;React&lt;/a&gt;. On React's landing page, you easily see what the framework is about.&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%2Fi%2Fsko2ek2o53mz6izn7sxe.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%2Fi%2Fsko2ek2o53mz6izn7sxe.png" alt="React home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Watching videos about the framework also helps kick start your learning. Good videos will expand on the problem the framework solves and if there are other frameworks solving the problem, the video explains the approach the framework takes and why it may be better than the others.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;As much as understanding the overview is very important, nothing is more important than code. The best way to learn code is to write code. When learning a new framework, you want to get to code as soon as possible because it's a different ball game entirely. Some frameworks have a good overview experience (OX, lol) but when it comes to code it's terrible.&lt;/p&gt;

&lt;p&gt;If the framework has tutorials on their documentation then it's probably the best place to start. It'll be good to just follow the tutorial, that's writing the code as explained in the tutorial. If the framework's documentation lacks tutorials then you may have to do a little search on the internet for tutorials.&lt;/p&gt;

&lt;p&gt;Depending on your experience level, this phase should take a few hours to days to get used to the basic parts of the framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Project&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Why learn a framework if you won't use it for building something?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Learning a framework should be done for a purpose. A framework is a tool for building something so while in the processing of learning a framework this should be taken most seriously. To explore the deep parts of a framework, you need to have a project that makes use of those parts of the framework.&lt;/p&gt;

&lt;p&gt;One way to learn really fast in this phase is to join an existing project with someone or a group of people who are experienced with the framework. This makes it easier for you to explore the framework. You can easily reach out to the experienced people on the project if you have questions or you're experiencing some blocker.&lt;/p&gt;

&lt;p&gt;If you are working on a personal project, you can still consult people with experience in the framework. Experienced people have a wealth of knowledge beyond the surface level, they can explain some methodologies used in the framework that'll make your learning experience very easy. They will also point out some nuances you may not be aware of (and sometimes that is not in the framework's documentation).&lt;/p&gt;

&lt;p&gt;To quickly evaluate how comfortable you will be with a framework, you can re-implement a former project with this new framework. Of course, this will take time if you are re-implementing a large project. If you do not have small projects, you can strip down features from a large project and implement only a few parts of it. Doing this allows you to compare your experience with this framework compared to other frameworks you have used.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Tinkering&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;At this phase, you are already comfortable with the framework to some extent. This is where you can flex your developer muscles and play around the framework. There are a number of things you can do here:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Experiment with config&lt;/strong&gt;: Frameworks usually come with configurations that have defaults. To really know how these configs work, you can change the defaults to different allowed values (You can attempt extreme values to see how the framework reacts). Doing this helps you understand better how the configuration affects the overall working of the framework.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Look into the source code&lt;/strong&gt;: A framework's source code is the single source of truth. You can learn a lot by studying the source code. Sometimes, documentation and tutorials are out-dated but the source code is never outdated. You should take this as practice. While studying a framework's source code, you may find some inefficiency and you can offer to contribute by opening an issue on Github or submitting a pull request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Play with the CLI&lt;/strong&gt;: If a framework comes with a Command Line Interface (CLI), then you should definitely play with the commands it comes with.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Community&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;No framework is perfect&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you use a framework long enough, you will find out it doesn't provide everything you want. Lots of frameworks have a community around them and this is where you find other people who have similar ideas, issues, or problems while using the framework. It's really beneficial to be active in the community because you get to meet really cool people and learn from them. You can even get to interact with the maintainers of the framework which is really cool!&lt;/p&gt;

&lt;p&gt;A good community will have a set of guidelines that will keep things organized. The members will also be welcoming and will always offer to help when raise questions or have issues. A good community may also showcase large projects that are using the framework, this gives anyone new to the framework some level of confidence in the framework.&lt;/p&gt;

&lt;p&gt;I hope this article will help you to get faster at learning new frameworks or technologies.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Happy coding!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>frameworks</category>
      <category>mastery</category>
      <category>tools</category>
    </item>
    <item>
      <title>Easy Deployment Setup With Bitbucket and AWS ECS</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Mon, 13 Jul 2020 17:57:00 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/easy-deployment-setup-with-bitbucket-and-aws-ecs-46ac</link>
      <guid>https://dev.to/olaoluwa98/easy-deployment-setup-with-bitbucket-and-aws-ecs-46ac</guid>
      <description>&lt;p&gt;Deployment is one of the most important parts of product development and launch. The better the deployment process is the faster it is. There are many deployment tools that make things easier today.&lt;/p&gt;

&lt;p&gt;In this article, I will take you through a deployment setup with Bitbucket and AWS Elastic Container Service (ECS).&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Basic knowledge of &lt;code&gt;git&lt;/code&gt; version control&lt;/li&gt;
&lt;li&gt;Basic knowledge of &lt;code&gt;Docker&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;A Bitbucket account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://bitbucket.org/" rel="noopener noreferrer"&gt;Bitbucket&lt;/a&gt; is a web-based version control repository hosting service owned by Atlassian. They have built-in Continuous Integration and Delivery/Deployment (CI/CD).&lt;/p&gt;

&lt;p&gt;We'll deploy a simple express app. Let's generate an express app&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx express-generator


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

&lt;/div&gt;

&lt;p&gt;If you don't have npx, you can install &lt;code&gt;express-generator&lt;/code&gt; globally&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; express-generator
express


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

&lt;/div&gt;

&lt;p&gt;Now we have our express app, let's create a docker file that we would use for deployment&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;touch &lt;/span&gt;Dockerfile


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

&lt;/div&gt;

&lt;p&gt;Copy this and paste in your &lt;code&gt;Dockerfile&lt;/code&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:8-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&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;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", "start" ]&lt;/span&gt;


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setup AWS ECS
&lt;/h2&gt;

&lt;p&gt;Login to your AWS account and navigate to &lt;a href="https://console.aws.amazon.com/ecs/home" rel="noopener noreferrer"&gt;ECS&lt;/a&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%2Fi%2F7mj71cdr0osi57nrjqtc.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%2Fi%2F7mj71cdr0osi57nrjqtc.png" alt="AWS ECS Home page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Navigate to &lt;strong&gt;Repositories&lt;/strong&gt; under Amazon Elastic Container Registry (ECR).&lt;/p&gt;

&lt;p&gt;AWS ECR is a container registry for docker. It's similar to Docker Hub. Container registries are used to store and distribute docker images.&lt;/p&gt;

&lt;p&gt;Create a repository by clicking the 'Create repository' button then give it a name like &lt;code&gt;my-express-app&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%2Fi%2Feeigwdzn6vzfwt7r4apd.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%2Fi%2Feeigwdzn6vzfwt7r4apd.png" alt="AWS ECR"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we have our repository URI: &lt;code&gt;XXXXXXXXXXX.region.amazonaws.com/my-express-app&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Pushing to AWS ECR
&lt;/h2&gt;

&lt;p&gt;We will build our docker image and push it to our newly created repository on ECR.&lt;br&gt;
For this article, we'll use &lt;code&gt;docker build&lt;/code&gt;. If you have a more complex project setup, you may want to consider &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;docker-compose&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;cd into the folder where the &lt;code&gt;Dockerfile&lt;/code&gt; is and run&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; my-express-app &lt;span class="nb"&gt;.&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;If the command ran well, you should have this:&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%2Fi%2Fyp3382z0s85dnpx8sd6t.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%2Fi%2Fyp3382z0s85dnpx8sd6t.png" alt="Run docker build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To push the image to ECR, you have to first install &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html" rel="noopener noreferrer"&gt;aws cli tool&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;aws2 configure&lt;/code&gt; to enter your AWS access ID and secret access key. Once you're done, run this command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="si"&gt;$(&lt;/span&gt;aws2 ecr get-login &lt;span class="nt"&gt;--no-include-email&lt;/span&gt; &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1&lt;span class="si"&gt;)&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Then push the docker image. For the &lt;code&gt;--region&lt;/code&gt; option, put your own region.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

docker tag my-express-app:latest XXXXXXXXXXX.region.amazonaws.com/my-express-app:latest
docker push XXXXXXXXXXX.region.amazonaws.com/my-express-app:latest


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Setup ECS Cluster
&lt;/h2&gt;

&lt;p&gt;Navigate to the Clusters page. Click Create Cluster.&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%2Fi%2F6j1xqf8k8xee9efxu3fj.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%2Fi%2F6j1xqf8k8xee9efxu3fj.png" alt="Creating a cluster"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will use EC2 Linux + Networking.&lt;/p&gt;

&lt;p&gt;You can use the following configuration to create the cluster:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Give your cluster a name.&lt;/li&gt;
&lt;li&gt;Create an empty cluster: Unchecked&lt;/li&gt;
&lt;li&gt;Provisioning Model: On-Demand Instance&lt;/li&gt;
&lt;li&gt;EC2 instance type: t2.nano (You can use whatever will fit your application needs)&lt;/li&gt;
&lt;li&gt;Number of instances: 1&lt;/li&gt;
&lt;li&gt;EC2 Ami Id: Amazon Linux 2 AMI [ami-08b26b905b0d17561]&lt;/li&gt;
&lt;li&gt;Root EBS Volume Size (GiB): 30&lt;/li&gt;
&lt;li&gt;Key pair: You can create anyone and attach it. This is the key you can use to ssh into the ec2 instance.&lt;/li&gt;
&lt;li&gt;Networking: You can create a new VPC or use an existing one.

&lt;ul&gt;
&lt;li&gt;Auto-assign public IP: Use subnet settings&lt;/li&gt;
&lt;li&gt;Security group: Create a one that opens up port 80&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;CloudWatch Container Insights: Unchecked&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Create an Application Load Balancer
&lt;/h2&gt;

&lt;p&gt;An Application Load Balancer allows us to dynamically assign applications to routes using pattern matching. This will be used in the ECS Service&lt;/p&gt;

&lt;p&gt;To create one, navigate to the load balancers tab on &lt;a href="//console.aws.amazon.com/ec2"&gt;EC2&lt;/a&gt; and click on Create Load Balancer&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%2Fi%2Fdku843c8ejl9czfpnjd0.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%2Fi%2Fdku843c8ejl9czfpnjd0.png" alt="Create Load Balancer"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Give it a name, fill the Availability Zones, and add a security group that exposes port 80 and 443 (if you want to enable SSL).&lt;/p&gt;

&lt;p&gt;In Step 4: Configure Routing, you'd create a target group. You can skip Step 5.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup ECS Task Definition &amp;amp; Service
&lt;/h2&gt;

&lt;p&gt;A task definition specifies the container information for our application. Navigate to Task Definitions and click on Create new Task Definition.&lt;/p&gt;

&lt;p&gt;Select EC2 as launch type compatibility&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%2Fi%2F19n9gzhbfe5n8zfsobqy.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%2Fi%2F19n9gzhbfe5n8zfsobqy.png" alt="Task definition"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the following configuration to create the task definition:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task Definition Name: my-express-app&lt;/li&gt;
&lt;li&gt;Task Role: Leave empty&lt;/li&gt;
&lt;li&gt;Network Mode: default&lt;/li&gt;
&lt;li&gt;Task memory (MiB): 128 (You can use whatever size that fits your application needs)&lt;/li&gt;
&lt;li&gt;Task CPU (unit): 128 (You can use whatever size that fits your application needs)&lt;/li&gt;
&lt;li&gt;Container: Click on Add container

&lt;ul&gt;
&lt;li&gt;Container name: my-express-app&lt;/li&gt;
&lt;li&gt;Image: XXXXXXXXXXX.region.amazonaws.com/my-express-app:latest&lt;/li&gt;
&lt;li&gt;Port mappings: Host - 0, Container port: 3000&lt;/li&gt;
&lt;li&gt;Configure the remaining to fit your application needs&lt;/li&gt;
&lt;li&gt;You can enable Log configuration so you can view the application logs on &lt;a href="https://console.aws.amazon.com/cloudwatch/home" rel="noopener noreferrer"&gt;CloudWatch&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you're done, click on Create. Next, we'll create a Service.&lt;br&gt;
A service lets you specify how many copies of your task definition to run and maintain in a cluster.&lt;/p&gt;

&lt;p&gt;Click the &lt;code&gt;Actions&lt;/code&gt; dropdown and select Create 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%2Fi%2Ffjt0agb2fh04wpuqksxa.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%2Fi%2Ffjt0agb2fh04wpuqksxa.png" alt="Creating an ecs service"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can use the following configuration to create the service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch type: EC2&lt;/li&gt;
&lt;li&gt;Task Definition: my-express-app&lt;/li&gt;
&lt;li&gt;Cluster: my-express-app (or whatever cluster you created)&lt;/li&gt;
&lt;li&gt;Service name: MyExpressAppService&lt;/li&gt;
&lt;li&gt;Service type: Replica&lt;/li&gt;
&lt;li&gt;Number of tasks: 1 (Or whatever number fits your application needs).&lt;/li&gt;
&lt;li&gt;Minimum healthy percent: 100&lt;/li&gt;
&lt;li&gt;Maximum percent: 200&lt;/li&gt;
&lt;li&gt;Deployment type: Rolling update&lt;/li&gt;
&lt;li&gt;Placement Templates: AZ Balanced Spread&lt;/li&gt;
&lt;li&gt;Load balancing: Application Load Balancer

&lt;ul&gt;
&lt;li&gt;Load balancer name: Select the load balancer we created earlier&lt;/li&gt;
&lt;li&gt;Container to load balance: Click on Add to load balancer&lt;/li&gt;
&lt;li&gt;Select the target group we created earlier or create a new one here&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Use default in the remaining steps or configure to your application needs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once the service is created, it'll run the task in the cluster.&lt;/p&gt;
&lt;h2&gt;
  
  
  Setup CD with Bitbucket
&lt;/h2&gt;

&lt;p&gt;We are going to create a new repository on Bitbucket. You can name it anything. I named mine &lt;code&gt;my-express-app&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%2Fi%2Fzca6vlqcalj5310emq24.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%2Fi%2Fzca6vlqcalj5310emq24.png" alt="Creating bitbucket repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Automated CI/CD comes built-in with Bitbucket. To enable it, navigate to Repository Settings &amp;gt; Pipelines &amp;gt; Settings and switch it on.&lt;/p&gt;
&lt;h2&gt;
  
  
  Bitbucket pipeline file
&lt;/h2&gt;

&lt;p&gt;Bitbucket uses a file named: bitbucket-pipelines.yml for automating CI/CD. Create the file.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;definitions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;push-image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;push-image&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build and Push Docker Image&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlassian/pipelines-awscli&lt;/span&gt;
      &lt;span class="na"&gt;caches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
      &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export BUILD_ID=$BITBUCKET_BRANCH_$BITBUCKET_COMMIT_$BITBUCKET_BUILD_NUMBER&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;export DOCKER_URI=$DOCKER_IMAGE_URL:latest&lt;/span&gt;
        &lt;span class="c1"&gt;# Login to docker registry on AWS&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;eval $(aws ecr get-login --no-include-email)&lt;/span&gt;
        &lt;span class="c1"&gt;# Build image&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker build -t $DOCKER_URI .&lt;/span&gt;
        &lt;span class="c1"&gt;# Push image to private registry&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;docker push $DOCKER_URI&lt;/span&gt;

    &lt;span class="na"&gt;deploy-to-ecs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nl"&gt;&amp;amp;deploy-to-ecs&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to ECS&lt;/span&gt;
      &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlassian/pipelines-awscli&lt;/span&gt;
      &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;pipe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;atlassian/aws-ecs-deploy:1.1.0&lt;/span&gt;
          &lt;span class="na"&gt;variables&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$AWS_ACCESS_KEY_ID&lt;/span&gt;
            &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$AWS_SECRET_ACCESS_KEY&lt;/span&gt;
            &lt;span class="na"&gt;AWS_DEFAULT_REGION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;$AWS_DEFAULT_REGION&lt;/span&gt;
            &lt;span class="na"&gt;CLUSTER_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-express-app'&lt;/span&gt;
            &lt;span class="na"&gt;SERVICE_NAME&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;MyExpressAppService'&lt;/span&gt;
            &lt;span class="na"&gt;TASK_DEFINITION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;task-definition.json"&lt;/span&gt;

&lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;master&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*push-image&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;step&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*deploy-to-ecs&lt;/span&gt;



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

&lt;/div&gt;

&lt;p&gt;You'd notice &lt;code&gt;TASK_DEFINITION&lt;/code&gt;. This is needed to update the ECS service for deployment. So let's create one:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

&lt;span class="nb"&gt;touch &lt;/span&gt;task-definition.json


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

&lt;/div&gt;

&lt;p&gt;Paste this in the task definition file&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&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;span class="nl"&gt;"containerDefinitions"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"logConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"logDriver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"awslogs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"awslogs-group"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/ecs/my-express-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"awslogs-region"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-east-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;own&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;region&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"awslogs-stream-prefix"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ecs"&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;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"portMappings"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"hostPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"protocol"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"containerPort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3000&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;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"XXXXXXXXXXX.region.amazonaws.com/my-express-app:latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"essential"&lt;/span&gt;&lt;span class="p"&gt;:&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="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-express-app"&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;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"memory"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"128"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-express-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"requiresCompatibilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"EC2"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cpu"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"128"&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;p&gt;Now we need to put the following environment variables on our bitbucket repository:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOCKER_IMAGE_URL&lt;/li&gt;
&lt;li&gt;AWS_DEFAULT_REGION&lt;/li&gt;
&lt;li&gt;AWS_ACCESS_KEY_ID&lt;/li&gt;
&lt;li&gt;AWS_SECRET_ACCESS_KEY&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Navigate to Repository Settings &amp;gt; Repository variables &amp;gt; &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%2Fi%2F5k9kb0946m1fn0jt3b0m.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%2Fi%2F5k9kb0946m1fn0jt3b0m.png" alt="Bitbucket repository variables"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you add them, commit and push to bitbucket to trigger the pipeline and the deployment process is run.&lt;/p&gt;

&lt;p&gt;The following things occur:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The docker image is built and pushed to the AWS ECR repository you created&lt;/li&gt;
&lt;li&gt;The task definition is updated with the &lt;code&gt;task-definition.json&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;The service (MyExpressAppService) is updated&lt;/li&gt;
&lt;li&gt;The service automatically registers a new instance of the task and begins draining the old task running&lt;/li&gt;
&lt;li&gt;The new task is dynamically registered on the Application Load Balancer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can check the full bitbucket repository &lt;a href="https://bitbucket.org/olaoluwa-98/my-express-app" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>deployment</category>
      <category>aws</category>
      <category>bitbucket</category>
      <category>docker</category>
    </item>
    <item>
      <title>Debugging Adonis With Chrome DevTools</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Wed, 22 Apr 2020 22:34:05 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/debugging-adonis-with-chrome-devtools-134b</link>
      <guid>https://dev.to/olaoluwa98/debugging-adonis-with-chrome-devtools-134b</guid>
      <description>&lt;p&gt;Debugging Node.js can be very difficult. Most times when something goes wrong it would take a while to get to the root of the problem because the error message may not be descriptive enough or&lt;br&gt;
there's a variable that you expect to have a value but it's &lt;code&gt;null&lt;/code&gt; or &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The first thing that comes to mind when debugging in Node.js is usually to use &lt;code&gt;console.log&lt;/code&gt;. This usually will get you a solution but in the long run, it wastes time.&lt;br&gt;
We've all been in a situation where we had to use &lt;code&gt;console.log&lt;/code&gt; multiple times because once was not enough. In a bid to quickly solve the problem we spend more time logging at different&lt;br&gt;
points of the application.&lt;/p&gt;

&lt;p&gt;But it does not have to be that way. There's a much simpler and more effective way of debugging in Node.js. It's by using a very simple keyword:&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="k"&gt;debugger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;As simple as this is, many people do not know about it. The keyword is more popular for Javascript on the browser because it doesn't need anything more than just typing it anywhere in your code.&lt;br&gt;
In Node.js it's a little different, you have to do more than just typing the keyword. To enable debugging in Node.js, in addition to adding &lt;code&gt;debugger;&lt;/code&gt; in your code, you have to run the application using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;node inspect &amp;lt;file_name.js&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are other ways to debug Node.js aside from &lt;code&gt;node-inspect&lt;/code&gt;, some are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chrome DevTools&lt;/strong&gt;: I'd expand more on this later in the article.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visual Studio Code&lt;/strong&gt;: It's the most effective if you already use VS Code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Studio&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Some JetBrains IDEs&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Eclipse IDE&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Debugging with Chrome DevTools
&lt;/h2&gt;

&lt;p&gt;We'll be using &lt;a href="https://adonisjs.com" rel="noopener noreferrer"&gt;AdonisJs&lt;/a&gt; (a Node.js web framework) as an example. To enable debugging mode on Adonis 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 serve &lt;span class="nt"&gt;--dev&lt;/span&gt; &lt;span class="nt"&gt;--debug&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fi%2Fc6r5i2hjkcegt1ieb5xw.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%2Fi%2Fc6r5i2hjkcegt1ieb5xw.png" alt="Adonis debug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This debugger makes use of &lt;strong&gt;Chrome DevTools&lt;/strong&gt; so head over to Chrome (If you have it installed). You should see the Node.js icon when you enable the DevTools. Clicking it will open a new window for debugging.&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%2Fi%2Fqlfi3vpfic4f5uz09h7t.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%2Fi%2Fqlfi3vpfic4f5uz09h7t.png" alt="Chrome dev tools"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Whenever the execution of your application encounters the keyword &lt;code&gt;debugger&lt;/code&gt;, it'll automatically pause execution and open the Chrome debugger window. You can do a lot of things in this window:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;See the value of scope and global variables&lt;/li&gt;
&lt;li&gt;View the call stack: allows you to see all the functions that were executed up until the current function being executed&lt;/li&gt;
&lt;li&gt;Resume execution&lt;/li&gt;
&lt;li&gt;Step over to the next function call&lt;/li&gt;
&lt;li&gt;Step into the next function call&lt;/li&gt;
&lt;li&gt;Step out of the current function&lt;/li&gt;
&lt;li&gt;Pause execution where exceptions are thrown&lt;/li&gt;
&lt;li&gt;and many more&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Voila! That's it. With this, you can easily debug your AdonisJs application and not have to &lt;code&gt;console.log&lt;/code&gt; everywhere😂.&lt;/p&gt;

&lt;p&gt;You can check &lt;a href="https://nodejs.org/api/debugger.html" rel="noopener noreferrer"&gt;Node.js docs&lt;/a&gt; for more information on debuggers.&lt;/p&gt;

</description>
      <category>node</category>
      <category>debugging</category>
      <category>adonisjs</category>
    </item>
    <item>
      <title>How to add custom validation rules to AdonisJs Validator</title>
      <dc:creator>Emmanuel Awotunde</dc:creator>
      <pubDate>Thu, 09 Apr 2020 05:58:04 +0000</pubDate>
      <link>https://dev.to/olaoluwa98/how-to-add-custom-validation-rules-to-adonisjs-validator-54d1</link>
      <guid>https://dev.to/olaoluwa98/how-to-add-custom-validation-rules-to-adonisjs-validator-54d1</guid>
      <description>&lt;p&gt;If you are reading this article, I assume you must have used &lt;em&gt;AdonisJs&lt;/em&gt; or you must have heard about the framework. &lt;br&gt;
&lt;a href="https://adonisjs.com" rel="noopener noreferrer"&gt;AdonisJs&lt;/a&gt; is a NodeJs framework that was inspired by Laravel. The framework was modeled after &lt;a href="https://laravel.com" rel="noopener noreferrer"&gt;Laravel&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Like most robust frameworks, &lt;em&gt;AdonisJs&lt;/em&gt; comes with a validator module that helps you in validating data (usually user input). However, the default validator does not come with every possible rule, you sometimes have to implement your own. The good news is that it is very easy to write custom rules and add them to the validator. In this article, I will walk you through how to do that.&lt;/p&gt;

&lt;p&gt;First, we have to setup our application - let's call it &lt;em&gt;MCU Character Checker&lt;/em&gt;. To start, install &lt;code&gt;adonis&lt;/code&gt; globally with:&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 &lt;span class="nt"&gt;-g&lt;/span&gt; @adonisjs/cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new application with:&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 mcu-character-checker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check &lt;a href="https://adonisjs.com/docs/4.1/installation" rel="noopener noreferrer"&gt;installation page&lt;/a&gt; for more information.&lt;br&gt;
Here is what our folder structure will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;├── app
│   ├── Middleware
│   └── Models
├── config
├── database
│   └── migrations
├── public
├── resources
│   └── views
└── start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the application server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;mcu-character-checker &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; adonis serve &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can open the application on &lt;a href="http://localhost:3333" rel="noopener noreferrer"&gt;localhost:3333&lt;/a&gt;, AdonisJs serves on port 3333 by default. You should have this page in the image below if everything ran correctly.&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%2Fi%2Fmmfmxabh8ui0rlh1rj6p.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%2Fi%2Fmmfmxabh8ui0rlh1rj6p.png" alt="Adonis Landing Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, let's create a page that collects data. We'll edit &lt;code&gt;start/routes.js&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replace the index route with this line:&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="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="s2"&gt;/&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="s2"&gt;CharacterController.showPage&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;p&gt;We have added our &lt;code&gt;/&lt;/code&gt; route, now we have to create our &lt;code&gt;CharacterController&lt;/code&gt; to handle this route. We'll do this 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 CharacterController &lt;span class="nt"&gt;--type&lt;/span&gt; http
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Great! Now we have our &lt;code&gt;CharacterController&lt;/code&gt;, let's create our &lt;code&gt;showPage&lt;/code&gt; method to handle the 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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;showPage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;view&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;view&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="s2"&gt;check-character&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the view for the route:&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:view check-character
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will create &lt;code&gt;resources/views/check-character.edge&lt;/code&gt;. Add the lines below to the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- Standard Meta --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"X-UA-Compatible"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"IE=edge,chrome=1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0, maximum-scale=5.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;
      Check MCU Characters
    &lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
      &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;auto&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nc"&gt;.form&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20vh&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nc"&gt;.form&lt;/span&gt; &lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;.form&lt;/span&gt; &lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;120px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;30px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;15px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;border-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt; Check for an MCU Character&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        {{ csrfField() }}
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"character"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Click to Check&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The page should look like this;&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%2Fi%2Ff5q1yt0ss5ttxq6d13o1.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%2Fi%2Ff5q1yt0ss5ttxq6d13o1.png" alt="MCU Character Checker landing page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our goal is to validate that a character (provided in the form) exists in the MCU. Obviously, this kind of validation may not be easy to achieve with the rules provided on AdonisJs validator so we will have to create a custom rule.&lt;/p&gt;

&lt;p&gt;The rule will check a list of names and validate that the provided name is for an MCU character. To create a custom rule we need to first install Adonis Validator. Run this command to install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;adonis &lt;span class="nb"&gt;install&lt;/span&gt; @adonisjs/validator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, register the validator provider inside the &lt;code&gt;start/app.js&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt; &lt;span class="o"&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;@adonisjs/validator/providers/ValidatorProvider&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;p&gt;To extend the validator, we'll implement our validation function and add it to &lt;code&gt;start/hooks.js&lt;/code&gt;. The file isn't part of our current setup, so we'll create it then add these lines to the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ioc&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adonisjs/fold&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="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;hooks&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@adonisjs/ignitor&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;p&gt;Adonis provides different hooks for different points in the application lifecycle. Adonis currently has 5 hooks namely: &lt;code&gt;providersRegistered&lt;/code&gt;, &lt;code&gt;providersBooted&lt;/code&gt;, &lt;code&gt;preloading&lt;/code&gt;, &lt;code&gt;httpServer&lt;/code&gt; and &lt;code&gt;aceCommand&lt;/code&gt;. For our use case, we'll use &lt;code&gt;providersRegistered&lt;/code&gt;. Next, we implement our validation function and extend the &lt;code&gt;Validator&lt;/code&gt;. Our validation function will have the following parameters, &lt;code&gt;data, field, message, args, get&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;data&lt;/code&gt; is an object containing the input fields and their values. In our case, it will look like this &lt;code&gt;{ character: 'Iron Man' }&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;field&lt;/code&gt; is the particular input field that is being validated which would be &lt;code&gt;character&lt;/code&gt; in our case.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;message&lt;/code&gt; is the error message that should be returned if the validation fails.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;args&lt;/code&gt; is a list of extra values passed in the validation rule.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;get&lt;/code&gt; is a function that is used to get the value of a key in an object (i.e data). To get the value of &lt;code&gt;character&lt;/code&gt;, we'll use &lt;code&gt;get(data, field)&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our validation function which will be in &lt;code&gt;start/hooks.js&lt;/code&gt; will 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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mcuCharacter&lt;/span&gt; &lt;span class="o"&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;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&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="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;get&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="c1"&gt;// get the character value&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * skip validation if value is not defined. `required` rule
     * should take care of it.
     */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// validate the character&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shortListOfMCUCharacters&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;iron man&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="s2"&gt;hulk&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="s2"&gt;spider-man&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="s2"&gt;loki&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="s2"&gt;thor&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="s2"&gt;odin&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="s2"&gt;black widow&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="s2"&gt;nick fury&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="s2"&gt;gamora&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="s2"&gt;black panther&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="s2"&gt;doctor strange&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="s2"&gt;groot&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="s2"&gt;ant-man&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="s2"&gt;captain america&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="s2"&gt;hawkeye&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="s2"&gt;wasp&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="s2"&gt;star-lord&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="s2"&gt;shuri&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="s2"&gt;valkrie&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="s2"&gt;dormammu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// if the character is not in the list, throw the validation error message&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;shortListOfMCUCharacters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
      &lt;span class="s2"&gt;`Nah, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; isn't part of the list as far as I am concerned`&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'll extend the &lt;code&gt;Validator&lt;/code&gt; with this new validation function.&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="nx"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mcuCharacter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mcuCharacter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note: the &lt;code&gt;Validator.extend&lt;/code&gt;'s first argument is a string, it represents how you would use this rule. It must be in camel case,  Ours is &lt;code&gt;mcuCharacter&lt;/code&gt; which would be &lt;code&gt;mc_character&lt;/code&gt; when using it as a rule.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We'll place this extension in the &lt;code&gt;providersRegistered&lt;/code&gt; hook. So our &lt;code&gt;start/hooks.js&lt;/code&gt; will 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="nx"&gt;hooks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;providersRegistered&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Validator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ioc&lt;/span&gt;&lt;span class="p"&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="s2"&gt;Validator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;Validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mcuCharacter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;mcuCharacter&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;blockquote&gt;
&lt;p&gt;Note: the &lt;code&gt;Validator&lt;/code&gt; in imported inside the &lt;code&gt;providersRegistered&lt;/code&gt; hook before it's in this hook that providers are registered so the &lt;code&gt;Validator&lt;/code&gt; cannot be accessed outside of this.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now that we have created our custom validation rule &lt;code&gt;mc_character&lt;/code&gt;, let's go ahead and use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ways to use Adonis Validator
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Route Level Validation&lt;/strong&gt;: This validates the &lt;code&gt;request&lt;/code&gt; payload before it proceeds to the &lt;code&gt;Controller&lt;/code&gt;. Check &lt;a href="https://adonisjs.com/docs/4.1/validator#_route_validator" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middleware Level Validation&lt;/strong&gt;: Here, you perform the validation in a middleware.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation in the Controller&lt;/strong&gt;: You perform the validation in the controller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can use any method you like or the one that suits your code structure. I use &lt;code&gt;Route Level Validation&lt;/code&gt; when I'm expecting a high number of input fields, I use &lt;code&gt;Middleware Level Validation&lt;/code&gt; whenever I need to access the &lt;code&gt;auth&lt;/code&gt; object&lt;br&gt;
and I used &lt;code&gt;Validation in the Controller&lt;/code&gt; when it's one or two validations I want to perform.&lt;/p&gt;

&lt;p&gt;In our example, we'll use &lt;code&gt;Validation in the Controller&lt;/code&gt;. Import the Validator in &lt;code&gt;CharacterController&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;validate&lt;/span&gt; &lt;span class="p"&gt;}&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;Validator&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;p&gt;We'll add a new route to receive the character in &lt;code&gt;start/routes.js&lt;/code&gt;:&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="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="s2"&gt;/&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="s2"&gt;CharacterController.checkCharacter&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;p&gt;Create the &lt;code&gt;checkCharacter&lt;/code&gt; method in &lt;code&gt;CharacterController&lt;/code&gt; to handle the request:&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;checkCharacter&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;view&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;view&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="s2"&gt;check-character&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's validate the character. Add these lines to the &lt;code&gt;checkCharacter&lt;/code&gt; method&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="c1"&gt;// create the rules for validation&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;character&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;required|mcu_character&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;validation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rules&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is part of the MCU, yay!`&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;validation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fails&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`Nah, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;character&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; isn't part of the list as far as I am concerned`&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;view&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="s2"&gt;check-character&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;message&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll modify our &lt;code&gt;check-character.edge&lt;/code&gt; template and add the message data. Add this below the submit button:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;{{ message }}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our application is now validating MCU characters!&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%2Fi%2Fnmfht1idrdlckzuy385a.gif" 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%2Fi%2Fnmfht1idrdlckzuy385a.gif" alt="MCU Character Checker final"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can check the full source code &lt;a href="https://github.com/olaoluwa-98/extending-adonis-validator-tutorial" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is also published on &lt;a href="https://codechauffeur.com/how-to-add-custom-validation-rules-to-adonis-validator" rel="noopener noreferrer"&gt;my website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>validation</category>
      <category>adonisjs</category>
    </item>
  </channel>
</rss>
