<?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>Forem: Yuen Ying Kit</title>
    <description>The latest articles on Forem by Yuen Ying Kit (@ykyuen).</description>
    <link>https://forem.com/ykyuen</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%2F27404%2Fbe1978b0-c1bb-4c68-9a93-b61d78f99aae.png</url>
      <title>Forem: Yuen Ying Kit</title>
      <link>https://forem.com/ykyuen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/ykyuen"/>
    <language>en</language>
    <item>
      <title>Setting the time interval of metrics collection in Boatswain</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Thu, 13 Feb 2020 14:20:18 +0000</pubDate>
      <link>https://forem.com/ykyuen/setting-the-time-interval-of-metrics-collection-in-boatswain-3lff</link>
      <guid>https://forem.com/ykyuen/setting-the-time-interval-of-metrics-collection-in-boatswain-3lff</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/setting-the-time-interval-of-metrics-collection-in-boatswain/"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Boatswain Agent 0.2.12 is released!
&lt;/h2&gt;

&lt;p&gt;Earlier this week we have released a new version of &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; (Agent version 0.2.12). Please follow this &lt;a href="https://docs.boatswain.io/boatswain-update-notes/#0-2-11-0-2-12"&gt;update guide&lt;/a&gt; for different Linux distros. If you are running &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; as a container, just use the 0.2.12 image available from &lt;a href="https://hub.docker.com/r/boatswainio/boatswain"&gt;Docker Hub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The new Period attribute
&lt;/h3&gt;

&lt;p&gt;In this release, we have added a new configurable attribute called &lt;strong&gt;Period&lt;/strong&gt; which is the collection time interval of the &lt;strong&gt;Server Host&lt;/strong&gt; and the &lt;strong&gt;Docker&lt;/strong&gt; metrics. Here is the new &lt;em&gt;/etc/boatswain.yml&lt;/em&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Please register and get the token from https://app.boatswain.io/&lt;/span&gt;
&lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token_here&lt;/span&gt;
&lt;span class="c1"&gt;# Period is the collection time interval of the host and docker metrics.&lt;/span&gt;
&lt;span class="c1"&gt;# CPU load could be reduced by using longer period.&lt;/span&gt;
&lt;span class="c1"&gt;#   - short   = 10s&lt;/span&gt;
&lt;span class="c1"&gt;#   - default = 30s&lt;/span&gt;
&lt;span class="c1"&gt;#   - long    = 60s&lt;/span&gt;
&lt;span class="na"&gt;period&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Prior to agent version 0.2.12, the collection time interval is 10s and there is not way to control it.&lt;/p&gt;

&lt;p&gt;Now, as stated in the above config file, there are 3 available options for the new &lt;strong&gt;Period&lt;/strong&gt; attribute and &lt;strong&gt;default&lt;/strong&gt; would be used if this attribute is missing.&lt;/p&gt;

&lt;h3&gt;
  
  
  The command flag for config file is updated too
&lt;/h3&gt;

&lt;p&gt;When running &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; directly through the binary as a foreground process, we could specify the location of the config file using the &lt;em&gt;-f&lt;/em&gt; flag (instead of &lt;em&gt;-t&lt;/em&gt; prior to agent version 0.2.12).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ykyuen@camus:~# boatswain --help

Usage: boatswain [options]
Options:
  -f string
      boatswain configuration file.
  -v  Show boatswain version and exit.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Server resources consumption VS Period
&lt;/h2&gt;

&lt;p&gt;Setting a longer period means the statistics shown on the &lt;a href="https://app.boatswain.io/"&gt;Boatswain web portal&lt;/a&gt; would have a less sample size but in return, it could reduce system load significantly. Moreover, it could free more data space for monitoring more &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; servers without hitting our BETA 2GB data limit.&lt;/p&gt;

&lt;p&gt;Let's run &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; to monitor itself with different &lt;strong&gt;Period&lt;/strong&gt; settings. Here are the three runs on a Digital Ocean droplet (1vCPU, 1GB Memory) and it hosts a Drupal 7 application. Each run lasts for 30 mins.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: The data size below only includes the metrics which depend on the &lt;strong&gt;Period&lt;/strong&gt; setting.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Period: short (10s)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cM_FnVN9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k4y8mcyom2cdb4e00937.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cM_FnVN9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k4y8mcyom2cdb4e00937.jpg" alt="Period: short (10s)"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CPU consumption:    1.39%
# Memory consumption: 10.06% (104,647,789 Bytes)
# Data size:          8.8MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Period: default (30s)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_41Cd4Nt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z1bbcrwgfe6ajq309iv3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_41Cd4Nt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/z1bbcrwgfe6ajq309iv3.jpg" alt="Period: default (30s)"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CPU consumption:    0.70%
# Memory consumption: 11.00% (114,425,856 Bytes)
# Data size:          4.3MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Period: long (60s)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Nuua3TEt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k2ncx3plyt4li1mctepg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Nuua3TEt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/k2ncx3plyt4li1mctepg.jpg" alt="Period: long (60s)"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# CPU consumption:    0.57%
# Memory consumption: 6,61% (68,772,546 Bytes)
# Data size:          1.9MB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Result
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;CPU consumption dropped significantly.

&lt;ul&gt;
&lt;li&gt;🔻 49.64% from &lt;strong&gt;1.39%&lt;/strong&gt; to &lt;strong&gt;0.70%&lt;/strong&gt; (Period: 10s ➡️ 30s)&lt;/li&gt;
&lt;li&gt;🔻 58.99% from &lt;strong&gt;1.39%&lt;/strong&gt; to &lt;strong&gt;0.57%&lt;/strong&gt; (Period: 10s ➡️ 60s)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Memory consumption was more or less the same.

&lt;ul&gt;
&lt;li&gt;Although the value dropped a lot (Period: 10s ➡️ 60s), it raised to &lt;strong&gt;11.90% (123,901,542 Bytes)&lt;/strong&gt; after running 6 hours.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Data size dropped significantly.

&lt;ul&gt;
&lt;li&gt;🔻 51.14% from &lt;strong&gt;8.8MB&lt;/strong&gt; to &lt;strong&gt;4.3MB&lt;/strong&gt; (Period: 10s ➡️ 30s)&lt;/li&gt;
&lt;li&gt;🔻 78.41% from &lt;strong&gt;8.8MB&lt;/strong&gt; to &lt;strong&gt;1.9MB&lt;/strong&gt; (Period: 10s ➡️ 60s)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Other metrics
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; also collects other metrics including&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Container Status&lt;/li&gt;
&lt;li&gt;Container Logs&lt;/li&gt;
&lt;li&gt;Web Analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They are &lt;strong&gt;independent&lt;/strong&gt; of the new &lt;strong&gt;Period&lt;/strong&gt; attribute as the logs and web analytics metrics are received in real time while the container status is monitored in a fixed 10s time interval.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;It has been more than one year since our BETA-I release and &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; looks more complete after the recent updates. Probably it's time to move on. 🚢&lt;/p&gt;

&lt;p&gt;Stay tuned with &lt;a href="https://twitter.com/BoatswainIO"&gt;us&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>boatswain</category>
      <category>docker</category>
    </item>
    <item>
      <title>Real time notification on Docker container status</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Tue, 21 Jan 2020 09:40:11 +0000</pubDate>
      <link>https://forem.com/ykyuen/real-time-notification-on-docker-container-status-lbg</link>
      <guid>https://forem.com/ykyuen/real-time-notification-on-docker-container-status-lbg</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/real-time-notification-on-docker-container-status/"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In the recent release of the &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; web portal (version 0.1.6), we have implemented a simple real time notification mechanism on the Docker container status. We hope this is helpful to engineer responding quickly to any unexpected issue happen on their container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the real time notification
&lt;/h2&gt;

&lt;p&gt;Now, &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; user could setup the real time notification on the &lt;strong&gt;Notification Settings&lt;/strong&gt; page which in under the &lt;strong&gt;Settings&lt;/strong&gt; menu on the top right hand corner.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kSkQm5N8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4ujrjkqxl3900mygtbrw.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kSkQm5N8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4ujrjkqxl3900mygtbrw.jpg" alt="Notification Settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable the real time notification
&lt;/h3&gt;

&lt;p&gt;Sometimes, not all the containers running on the &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; server are our concerns. So we allow user to enable the notification feature selectively by using regular expression. Any containers with name matched with the regular expressions would have notification enabled.&lt;/p&gt;

&lt;p&gt;Here are the two rules when setting up the regular expression:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Include the &lt;code&gt;/&lt;/code&gt; before and after.&lt;/li&gt;
&lt;li&gt;Only accepts the &lt;code&gt;i&lt;/code&gt; flag.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AUt5FLVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wpk8wmoko5t8iczys431.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AUt5FLVX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/wpk8wmoko5t8iczys431.jpg" alt="Configure the regular expression to enable notification"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Check out which container have notification enabled
&lt;/h3&gt;

&lt;p&gt;Below the regular expression form, there is a list showing the containers which have notification enabled. Any detected containers in the recent 24 hours will be listed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fd8s3FrX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qgfsizw45e1fsni7e2kt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fd8s3FrX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/qgfsizw45e1fsni7e2kt.jpg" alt="List of notification enabled containers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please note that the above list is just for reference and any newly added container would also have notification enabled as long as its name matched any regular expression.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receive the notification email
&lt;/h3&gt;

&lt;p&gt;Whenever the container status is changed, the email address associated with the corresponding &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; account would receive an notification email. Here is an example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Hi ykyuen,

We have detected a status change of the following container:
---
Host:            camus
Container ID:    1d2ce3c96b372fc61622c0c0133efda6de24cd2fad2e8faab810b8539d3ce4a1
Container name:  nginx-test
Container image: nginx:latest
Command:         nginx -g 'daemon off;'
Status change:   running -&amp;gt; exited
Exit code:       0
Error:           
Is OOM killed:   No
---

- Boatswain Team
 ____              _                     _
|  _ \            | |                   (_)
| |_) | ___   __ _| |_ _____      ____ _ _ _ __
|  _ &amp;lt; / _ \ / _` | __/ __\ \ /\ / / _` | | '_ \
| |_) | (_) | (_| | |_\__ \\ V  V / (_| | | | | |
|____/ \___/ \__,_|\__|___/ \_/\_/ \__,_|_|_| |_|
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;We notice that &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; consumes certain amount of server resources and user might hang back especially when his/her application is running on a small instance. So we are working on the Boatswain configuration and let user decide the frequency of the metrics and log collections.&lt;/p&gt;

&lt;p&gt;Lastly, happy coding 👨‍💻 and wishing all the best to all of you 🎊 🐀 🎉.&lt;/p&gt;

</description>
      <category>boatswain</category>
      <category>docker</category>
    </item>
    <item>
      <title>Monitor Kubernetes cluster by running Boatswain as a DaemonSet</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Thu, 09 Jan 2020 09:04:45 +0000</pubDate>
      <link>https://forem.com/ykyuen/monitor-kubernetes-cluster-by-running-boatswain-as-a-daemonset-3p73</link>
      <guid>https://forem.com/ykyuen/monitor-kubernetes-cluster-by-running-boatswain-as-a-daemonset-3p73</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/monitor-k8s-cluster-by-running-boatswain-as-a-daemonset/"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In a &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; cluster, each node has a container runtime for running containers in pods. &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; supports various &lt;a href="https://kubernetes.io/docs/setup/production-environment/container-runtimes/"&gt;container runtimes&lt;/a&gt; including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://containerd.io/"&gt;containerd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cri-o.io/"&gt;CRI-O&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if the &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; cluster is using &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; as container runtime, we could install &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; on the nodes and monitoring its status as well as collecting the container logs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE: The example in this article is for experimental purpose and we do not suggest using &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; in any production &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; cluster.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The DaemonSet in Kubernetes
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt;, we could deploy the &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; pod as a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt;. Unlike a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/"&gt;Deployment&lt;/a&gt; which we could replicates multiple pods across different nodes, a &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt; makes sure that a single pod runs on the selected nodes even if the node is newly added to the cluster. It is particular useful for storage daemon, log collection and monitoring on the node.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Boatswain as a DaemonSet
&lt;/h2&gt;

&lt;p&gt;Here are the steps about setting up the &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt; in a &lt;a href="https://kubernetes.io/"&gt;Kubernetes&lt;/a&gt; cluster.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create the Boatswain namespace&lt;/li&gt;
&lt;li&gt;Setup the Boatswain token as a secret&lt;/li&gt;
&lt;li&gt;Setup the config file of the Boatswain DaemonSet&lt;/li&gt;
&lt;li&gt;Start the Boatswain DaemonSet&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Create the Boatswain namespace
&lt;/h3&gt;

&lt;p&gt;Let's create a new namespace to separate the &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; setup from those already exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create namespace boatswain
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup the Boatswain token as a secret
&lt;/h3&gt;

&lt;p&gt;This token is required for running &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt;. We store it as a secret called &lt;strong&gt;boatswain&lt;/strong&gt; and later use it in the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt; configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic boatswain &lt;span class="nt"&gt;--from-literal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;TO_BE_REPLACED&amp;gt; &lt;span class="nt"&gt;-n&lt;/span&gt; boatswain
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup the config file of the Boatswain DaemonSet
&lt;/h3&gt;

&lt;p&gt;Here comes the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt; configuration.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;daemon-set.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;DaemonSet&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&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;boatswainio/boatswain:&amp;lt;latest or tag&amp;gt;&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;BOATSWAIN_TOKEN&lt;/span&gt;
          &lt;span class="na"&gt;valueFrom&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;secretKeyRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;boatswain&lt;/span&gt;
              &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;token&lt;/span&gt;
        &lt;span class="na"&gt;securityContext&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NET_ADMIN"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;volumeMounts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dockersock&lt;/span&gt;
            &lt;span class="na"&gt;mountPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/var/run/docker.sock"&lt;/span&gt;
      &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dockersock&lt;/span&gt;
        &lt;span class="na"&gt;hostPath&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/var/run/docker.sock&lt;/span&gt;
      &lt;span class="na"&gt;hostNetwork&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;hostPID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
      &lt;span class="na"&gt;restartPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Always&lt;/span&gt;
      &lt;span class="na"&gt;nodeSelector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="s"&gt;kubernetes.io/hostname&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;hostname of the selected node&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Before saving the yaml file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Replace the version of &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; at line 17.&lt;/li&gt;
&lt;li&gt;Set the hostname of the target node which you want to install &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; or remove line 37 and 38 for installation on all nodes.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Start the Boatswain DaemonSet
&lt;/h3&gt;

&lt;p&gt;Execute the following command to start the &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create &lt;span class="nt"&gt;-f&lt;/span&gt; daemon-set.yaml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Check the status of the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/"&gt;DaemonSet&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;ykyuen@camus ~]&lt;span class="nv"&gt;$ &lt;/span&gt;kubectl get ds &lt;span class="nt"&gt;-n&lt;/span&gt; boatswain
NAME        DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR                                                        AGE
boatswain   1         1         1       1            1           kubernetes.io/hostname&lt;span class="o"&gt;=&lt;/span&gt;gke-boatswain-default-pool-v2-1234abcd-5678   52s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And we could read the metrics and logs on &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yVHPwQ5---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kbjqkmea9o1hlkunsvf8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yVHPwQ5---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kbjqkmea9o1hlkunsvf8.png" alt="Status of the Kubernetes node"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;The example above shows that it is possible to use &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; to monitor the &lt;a href="https://kubernetes.io/"&gt;Kuberenetes&lt;/a&gt; cluster. But currently it might not able to show the network metrics (confirmed on GKE cluster above). It might be related to the security settings and so far we haven't investigated further about this issue. Moreover, running &lt;a href="https://boatswain.io/"&gt;Boatswain&lt;/a&gt; on all nodes does not work well as the usage will hit the 2GB data limit of the beta trial in a few hours. If you have any suggestions or thoughts, please let us know. 😀&lt;/p&gt;

</description>
      <category>boatswain</category>
      <category>docker</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Monitor your Docker container status in real time</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Fri, 20 Dec 2019 09:00:09 +0000</pubDate>
      <link>https://forem.com/ykyuen/monitor-your-docker-container-status-in-real-time-52bn</link>
      <guid>https://forem.com/ykyuen/monitor-your-docker-container-status-in-real-time-52bn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/monitor-your-docker-container-status-in-real-time/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The new Container Status dashboard!
&lt;/h2&gt;

&lt;p&gt;In the recent update of &lt;a href="https://boatswain.io/" rel="noopener noreferrer"&gt;Boatswain&lt;/a&gt; (agent version 0.2.11), it keeps track of all the container statuses, no matter running or stopped, and display them on the new &lt;strong&gt;Container Status&lt;/strong&gt; dashboard implemented on the &lt;a href="https://boatswain.io/" rel="noopener noreferrer"&gt;Boatswain.io&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Container Status Timeline
&lt;/h3&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fry828rdy0yr3hcars72h.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fry828rdy0yr3hcars72h.png" alt="Container Status Timeline"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the timeline above, we could get a rough idea on the recent lifecycle of any container. There are all together 8 possible statuses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;created&lt;/li&gt;
&lt;li&gt;running&lt;/li&gt;
&lt;li&gt;paused&lt;/li&gt;
&lt;li&gt;restarting&lt;/li&gt;
&lt;li&gt;exited&lt;/li&gt;
&lt;li&gt;dead&lt;/li&gt;
&lt;li&gt;removing&lt;/li&gt;
&lt;li&gt;unknown&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that &lt;a href="https://boatswain.io/" rel="noopener noreferrer"&gt;Boatswain&lt;/a&gt; makes his best effort to collect the container status and may not be able to acknowledge a change if a status duration is too short.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Container Info
&lt;/h3&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa9rubss5wfjzqo14ljgw.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fa9rubss5wfjzqo14ljgw.png" alt="Container Info"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This pane displays the current container status which is equivalent to the &lt;code&gt;docker ps&lt;/code&gt; command.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Container Status History
&lt;/h3&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnkpy7cge4m1df0ol41a5.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fnkpy7cge4m1df0ol41a5.png" alt="Container Status History"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This table list out every change in status detected and it is just the textual format representing the timeline graph above. The first row with highlighted background is the current container status.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check out the latest status of all containers
&lt;/h3&gt;

&lt;p&gt;Other than the new &lt;strong&gt;Container Status&lt;/strong&gt; dashboard, we also added a new pane in the &lt;strong&gt;Docker Status&lt;/strong&gt; dashboard listing the current status of all the containers.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5ciqtvknsxuqbwjooowy.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F5ciqtvknsxuqbwjooowy.png" alt="List of all container status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next?
&lt;/h2&gt;

&lt;p&gt;We hope the above new feature could help &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; users getting up-to-date information of their &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; servers but dashboard is a just passive solution which means it is futile if you are not looking at it. &lt;strong&gt;Real time notification&lt;/strong&gt; could fill this gap and that's our final stage of development before the official launch. Stay tuned and follow us on &lt;a href="https://twitter.com/BoatswainIO" rel="noopener noreferrer"&gt;twitter&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>boatswain</category>
      <category>docker</category>
    </item>
    <item>
      <title>Handling HTTP request in Go Echo framework (2)</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Thu, 18 Apr 2019 09:24:54 +0000</pubDate>
      <link>https://forem.com/ykyuen/handling-http-request-in-go-echo-framework-2-29ii</link>
      <guid>https://forem.com/ykyuen/handling-http-request-in-go-echo-framework-2-29ii</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/handling-http-request-in-go-echo-framework-2/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;This is the second post about handling HTTP request in &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; framework and we will continue to work on the example we made previously.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.boatswain.io/post/handling-http-request-in-go-echo-framework-1/" rel="noopener noreferrer"&gt;Handling HTTP request in Go Echo framework (1)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This time we will create a simple HTML form and submit it as a POST request.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a POST request endpoint
&lt;/h2&gt;

&lt;p&gt;Checkout this &lt;a href="https://gitlab.com/ykyuen/handling-http-request-in-go-echo-example-1" rel="noopener noreferrer"&gt;repo&lt;/a&gt; and create the &lt;em&gt;api/post_full_name.go&lt;/em&gt; to handle the POST request. This new file is almost the same as &lt;em&gt;api/get_full_name.go&lt;/em&gt; except the JSON is prettified before returning to the client.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;api/post_full_name.go&lt;/code&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"bytes"&lt;/span&gt;
  &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;
  &lt;span class="s"&gt;"fmt"&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;

  &lt;span class="s"&gt;"gitlab.com/ykyuen/handling-http-request-in-go-echo-example-1/model"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;PostFullName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Bind the input data to ExampleRequest&lt;/span&gt;
  &lt;span class="n"&gt;exampleRequest&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExampleRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Manipulate the input data&lt;/span&gt;
  &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;

  &lt;span class="c"&gt;// Pretty print the json []byte&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{
      "first_name": %q,
      "last_name": %q,
      "msg": "Hello %s"
    }`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Indent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"  "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Return the json to the client&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Add the new route in &lt;em&gt;main.go&lt;/em&gt;.&lt;/p&gt;

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

&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Echo instance&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Instantiate a template registry with an array of template set&lt;/span&gt;
  &lt;span class="c"&gt;// Ref: https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"home.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/home.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"about.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Route =&amp;gt; handler&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HomeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Route =&amp;gt; api&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/get-full-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetFullName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/post-full-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PostFullName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Start the Echo server&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&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;h3&gt;
  
  
  Test the new endpoint using curl
&lt;/h3&gt;

&lt;p&gt;Run the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server as send a POST request using &lt;strong&gt;curl&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

curl http://localhost:1323/api/post-full-name &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{ "first_name": "Kit", "last_name": "Yuen"  }'&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here is the example result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm3c31s82rmgg8pki4wh.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbm3c31s82rmgg8pki4wh.jpg" alt="A JSON is return based on our POST request payload."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add an HTML form
&lt;/h2&gt;

&lt;p&gt;The POST request endpoint is ready and now we could add an HTML form and complete the whole setup. Let's add the form in the about page.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;view/about.html&lt;/code&gt;&lt;/p&gt;

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

{{define "title"}}
  Boatswain Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{index . "msg"}}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;This is the about page.&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;

  &lt;span class="c"&gt;&amp;lt;!-- HTML form --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"post-full-name-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &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;id=&lt;/span&gt;&lt;span class="s"&gt;"first-name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"First Name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &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;id=&lt;/span&gt;&lt;span class="s"&gt;"last-name"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Last Name"&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;"button"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"submit-btn"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&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="c"&gt;&amp;lt;!-- Print the response after the jQuery ajax request --&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;pre&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"form-result"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/pre&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text/javascript"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="c1"&gt;// Send a ajax request when the submit button is clicked&lt;/span&gt;
    &lt;span class="nf"&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;#submit-btn&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#first-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;#last-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;val&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/post-full-name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;first_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;last_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;lastName&lt;/span&gt;
        &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="na"&gt;processData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;contentType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
          &lt;span class="nf"&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;#form-result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&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="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;fail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
          &lt;span class="nf"&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;#form-result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST request failed!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
{{end}}


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

&lt;/div&gt;

&lt;p&gt;As the form submission required &lt;strong&gt;jQuery&lt;/strong&gt;, let's include it in the &lt;em&gt;view/base.html&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;view/base.html&lt;/code&gt;&lt;/p&gt;


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

&lt;p&gt;{{define "base.html"}}&lt;br&gt;
  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br&gt;
      &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;{{template "title" .}}&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;br&gt;
      &lt;span class="c"&gt;&amp;lt;!-- jQuery --&amp;gt;&lt;/span&gt;&lt;br&gt;
      &lt;span class="nt"&gt;&amp;lt;script&lt;br&gt;
        &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"&lt;a href="https://code.jquery.com/jquery-3.3.1.min.js" rel="noopener noreferrer"&gt;https://code.jquery.com/jquery-3.3.1.min.js&lt;/a&gt;"&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;integrity=&lt;/span&gt;&lt;span class="s"&gt;"sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="&lt;/span&gt;&lt;br&gt;
        &lt;span class="na"&gt;crossorigin=&lt;/span&gt;&lt;span class="s"&gt;"anonymous"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br&gt;
      {{template "body" .}}&lt;br&gt;
    &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;br&gt;
{{end}}&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Test the HTML form in the about page&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Start the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server and browse the about page. Fill in the first and last name and then click the submit button. It should show the response JSON as follow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkf5jftvrxey868fxfy1w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkf5jftvrxey868fxfy1w.jpg" alt="Click the submit button and get the response."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The project structure
&lt;/h3&gt;

&lt;p&gt;Here is our new project structure. &lt;em&gt;(The project is renamed to &lt;strong&gt;handling-http-request-in-go-echo-example-2&lt;/strong&gt;, make sure you set the &lt;strong&gt;import&lt;/strong&gt; statement in the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt; source files correctly if you want to change the project name.)&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;handling-http-request-in-go-echo-example-2/&lt;br&gt;
  ├── api/                     &lt;span class="c"&gt;# folder of api endpoints&lt;/span&gt;&lt;br&gt;
  │   ├── get_full_name.go     &lt;span class="c"&gt;# api for get full name&lt;/span&gt;&lt;br&gt;
  │   ├── post_full_name.go    &lt;span class="c"&gt;# api for post full name&lt;/span&gt;&lt;br&gt;
  ├── handler/                 &lt;span class="c"&gt;# folder of request handlers&lt;/span&gt;&lt;br&gt;
  │   ├── home_handler.go      &lt;span class="c"&gt;# handler for home page&lt;/span&gt;&lt;br&gt;
  │   └── about_handler.go     &lt;span class="c"&gt;# handler for about page&lt;/span&gt;&lt;br&gt;
  ├── model/                   &lt;span class="c"&gt;# folder of custom struct types&lt;/span&gt;&lt;br&gt;
  │   ├── example_request.go   &lt;span class="c"&gt;# struct type of get_full_name request&lt;/span&gt;&lt;br&gt;
  │   └── example_response.go  &lt;span class="c"&gt;# hstruct type of get_full_name response&lt;/span&gt;&lt;br&gt;
  ├── vendor/                  &lt;span class="c"&gt;# dependencies managed by dep&lt;/span&gt;&lt;br&gt;
  │   ├── github.com/&lt;span class="k"&gt;&lt;em&gt;&lt;/em&gt;&lt;/span&gt;&lt;br&gt;
  │   └── golang.org/&lt;span class="k"&gt;&lt;/span&gt;&lt;br&gt;
  ├── view/                    &lt;span class="c"&gt;# folder of html templates&lt;/span&gt;&lt;br&gt;
  │   ├── base.html            &lt;span class="c"&gt;# base layout template&lt;/span&gt;&lt;br&gt;
  │   ├── home.html            &lt;span class="c"&gt;# home page template&lt;/span&gt;&lt;br&gt;
  │   └── about.html           &lt;span class="c"&gt;# about page template&lt;/span&gt;&lt;br&gt;
  ├── Gopkg.lock               &lt;span class="c"&gt;# dep config file&lt;/span&gt;&lt;br&gt;
  ├── Gopkg.toml               &lt;span class="c"&gt;# dep config file&lt;/span&gt;&lt;br&gt;
  └── main.go                  &lt;span class="c"&gt;# programme entrypoint&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;This is the second episode of &lt;a href="https://blog.boatswain.io/post/handling-http-request-in-go-echo-framework-1/" rel="noopener noreferrer"&gt;Handling HTTP request in Go Echo framework (1)&lt;/a&gt; and we have added the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setup a POST request endpoint in the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; framework.&lt;/li&gt;
&lt;li&gt;Prettify the JSON byte array&lt;/li&gt;
&lt;li&gt;Add an HTML form and bind it to the new POST request using AJAX in jQuery/javascript.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The complete example could be found on &lt;a href="https://gitlab.com/ykyuen/handling-http-request-in-go-echo-example-2" rel="noopener noreferrer"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>echo</category>
    </item>
    <item>
      <title>Handling HTTP request in Go Echo framework (1)</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Mon, 08 Apr 2019 17:31:20 +0000</pubDate>
      <link>https://forem.com/ykyuen/handling-http-request-in-go-echo-framework-1-5ack</link>
      <guid>https://forem.com/ykyuen/handling-http-request-in-go-echo-framework-1-5ack</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/handling-http-request-in-go-echo-framework-1/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;In the last post, we have discussed about how we could setup nested templates in &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; framework.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.boatswain.io/post/setup-nested-html-template-in-go-echo-web-framework/" rel="noopener noreferrer"&gt;Setup nested HTML template in Go Echo web framework&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the following sections, we will move on and see how we could make HTTP request in &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server and render the result back to the client. Let's start with the &lt;a href="https://gitlab.com/ykyuen/golang-echo-template-example" rel="noopener noreferrer"&gt;example&lt;/a&gt; we did in the last article.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup an API endpoint
&lt;/h2&gt;

&lt;p&gt;Firstly, create a new API endpoint and return a simple JSON which is later called by the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create new endpoint in the api folder
&lt;/h3&gt;

&lt;p&gt;Unlike a hardcoded JSON request, our new API endpoint takes the request input from JSON data, form data or query parameters as defined in the &lt;em&gt;model/example_request.go&lt;/em&gt; and then return it the the client.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;model/example_request.go&lt;/em&gt;&lt;/p&gt;

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

&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ExampleRequest&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"first_name" form:"first_name" query:"first_name"`&lt;/span&gt;
  &lt;span class="n"&gt;LastName&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"last_name" form:"last_name" query:"last_name"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;&lt;em&gt;api/get_full_name.go&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"fmt"&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="s"&gt;"gitlab.com/ykyuen/golang-echo-template-example/model"&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetFullName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// Bind the input data to ExampleRequest&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;exampleRequest&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExampleRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Manipulate the input data&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;greeting&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
      &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&lt;code&gt;{&lt;br&gt;
        "first_name": %q,&lt;br&gt;
        "last_name": %q,&lt;br&gt;
        "msg": "Hello %s"&lt;br&gt;
      }&lt;/code&gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FirstName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exampleRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LastName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Setup the route for the above API endpoint&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Add our new API endpoint route in _main.go*.&lt;/p&gt;


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

&lt;p&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;br&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// Echo instance&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Instantiate a template registry with an array of template set&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// Ref: &lt;a href="https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678" rel="noopener noreferrer"&gt;https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678&lt;/a&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"home.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/home.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"about.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Route =&amp;gt; handler&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HomeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Route =&amp;gt; api&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/get-full-name"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetFullName&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Start the Echo server&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Test the new API endpoint&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Run the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server as see if it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxebwoy8mb4jftr5m72jq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxebwoy8mb4jftr5m72jq.jpg" alt="It works!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This new endpoint could serve the browser client directly or it could be called by the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Call the API from Echo server
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the response struct type
&lt;/h3&gt;

&lt;p&gt;Similar to the &lt;em&gt;model/example_request.go&lt;/em&gt;, we need to define another struct type for the HTTP response.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;model/example_response.go&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ExampleResponse&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;FirstName&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"first_name"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;LastName&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"last_name"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;Msg&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;&lt;code&gt;json:"msg"&lt;/code&gt;&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Show the new greeting message in the about page&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Let's modify the about page handler such that it will show the greeting message.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;handler/about_handler.go&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"encoding/json"&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"io/ioutil"&lt;/span&gt;&lt;br&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="s"&gt;"gitlab.com/ykyuen/golang-echo-template-example/model"&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AboutHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="n"&gt;tr&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tr&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Call the api&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"&lt;a href="http://localhost:1323/api/get-full-name?first_name=Kit&amp;amp;last_name=Yuen" rel="noopener noreferrer"&gt;http://localhost:1323/api/get-full-name?first_name=Kit&amp;amp;amp;last_name=Yuen&lt;/a&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;br&gt;
  &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Unmarshal the response into a ExampleResponse struct&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;exampleResponse&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExampleResponse&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unmarshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;exampleResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="c"&gt;// Please note the the second parameter "about.html" is the template name and should&lt;/span&gt;&lt;br&gt;
  &lt;span class="c"&gt;// be equal to one of the keys in the TemplateRegistry array defined in main.go&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
    &lt;span class="s"&gt;"msg"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;exampleResponse&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;br&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Test the about page&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;Start the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server and browse the about page. We could see the new greeting message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ip62i33agdekw2qy3jd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3ip62i33agdekw2qy3jd.jpg" alt="The greeting msg is now composed of the result of the API call."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The project structure
&lt;/h3&gt;

&lt;p&gt;After making the above changes, the project structure should look like this. &lt;em&gt;(The project is renamed to &lt;strong&gt;handling-http-request-in-go-echo-example-1&lt;/strong&gt;, make sure you set the &lt;strong&gt;import&lt;/strong&gt; statement in the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt; source files correctly if you want to change the project name.)&lt;/em&gt;&lt;/p&gt;


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

&lt;p&gt;handling-http-request-in-go-echo-example-1/&lt;br&gt;
  ├── api/                     &lt;span class="c"&gt;# folder of api endpoints&lt;/span&gt;&lt;br&gt;
  │   ├── get_full_name.go     &lt;span class="c"&gt;# api for get full name&lt;/span&gt;&lt;br&gt;
  ├── handler/                 &lt;span class="c"&gt;# folder of request handlers&lt;/span&gt;&lt;br&gt;
  │   ├── home_handler.go      &lt;span class="c"&gt;# handler for home page&lt;/span&gt;&lt;br&gt;
  │   └── about_handler.go     &lt;span class="c"&gt;# handler for about page&lt;/span&gt;&lt;br&gt;
  ├── model/                   &lt;span class="c"&gt;# folder of custom struct types&lt;/span&gt;&lt;br&gt;
  │   ├── example_request.go   &lt;span class="c"&gt;# struct type of get_full_name request&lt;/span&gt;&lt;br&gt;
  │   └── example_response.go  &lt;span class="c"&gt;# hstruct type of get_full_name response&lt;/span&gt;&lt;br&gt;
  ├── vendor/                  &lt;span class="c"&gt;# dependencies managed by dep&lt;/span&gt;&lt;br&gt;
  │   ├── github.com/&lt;span class="k"&gt;&lt;em&gt;&lt;/em&gt;&lt;/span&gt;&lt;br&gt;
  │   └── golang.org/&lt;span class="k"&gt;&lt;/span&gt;&lt;br&gt;
  ├── view/                    &lt;span class="c"&gt;# folder of html templates&lt;/span&gt;&lt;br&gt;
  │   ├── base.html            &lt;span class="c"&gt;# base layout template&lt;/span&gt;&lt;br&gt;
  │   ├── home.html            &lt;span class="c"&gt;# home page template&lt;/span&gt;&lt;br&gt;
  │   └── about.html           &lt;span class="c"&gt;# about page template&lt;/span&gt;&lt;br&gt;
  ├── Gopkg.lock               &lt;span class="c"&gt;# dep config file&lt;/span&gt;&lt;br&gt;
  ├── Gopkg.toml               &lt;span class="c"&gt;# dep config file&lt;/span&gt;&lt;br&gt;
  └── main.go                  &lt;span class="c"&gt;# programme entrypoint&lt;/span&gt;&lt;/p&gt;

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

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Summary&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;This article shows you how to setup a simple API endpoint in &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; framework. Since &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; is a &lt;strong&gt;strongly typed&lt;/strong&gt; language, we have to convert the JSON into well defined struct type before for we could manipulate its content. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binding the GET request input to &lt;strong&gt;exampleRequest&lt;/strong&gt; in &lt;em&gt;api/get_full_name.go&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Unmarshal the GET response into &lt;strong&gt;exampleResponse&lt;/strong&gt; in &lt;em&gt;handler/about_handler.go&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To invoke the API call, we could simply make use of the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; standard &lt;a href="https://golang.org/pkg/net/http/" rel="noopener noreferrer"&gt;net/http&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;The complete example could be found on &lt;a href="https://gitlab.com/ykyuen/handling-http-request-in-go-echo-example-1" rel="noopener noreferrer"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>echo</category>
    </item>
    <item>
      <title>Setup nested HTML template in Go Echo web framework</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Tue, 20 Nov 2018 16:49:41 +0000</pubDate>
      <link>https://forem.com/ykyuen/setup-nested-html-template-in-go-echo-web-framework-e9b</link>
      <guid>https://forem.com/ykyuen/setup-nested-html-template-in-go-echo-web-framework-e9b</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/setup-nested-html-template-in-go-echo-web-framework/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; is a lightweight but complete web framework in &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; for building RESTful API. It is fast and includes a bunch of middleware for handling the whole HTTP request-response cycle. For the rendering part, it works with any template engine but i pick the standard &lt;a href="https://godoc.org/html/template" rel="noopener noreferrer"&gt;html/template&lt;/a&gt; package for the purpose of simplicity. And at the end of this article, a nested template &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; project setup is demonstrated.&lt;/p&gt;

&lt;p&gt;If you already have an idea on how &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; works, jump to the &lt;a href="https://blog.boatswain.io/post/setup-nested-html-template-in-go-echo-web-framework/#using-nested-template" rel="noopener noreferrer"&gt;Using nested template section&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A basic Echo project setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the project folder under proper $GOPATH
&lt;/h3&gt;

&lt;p&gt;The complete project code is hosted on &lt;a href="https://gitlab.com/ykyuen/golang-echo-template-example" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt; so we first create the project folder &lt;em&gt;$GOPATH/src/gitlab.com/ykyuen/golang-echo-template-example&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create the &lt;em&gt;main.go&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;Inside the newly created folder, let's just copy the hello world example from the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; official site and create the &lt;em&gt;main.go&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&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;h3&gt;
  
  
  Download the Echo package using dep
&lt;/h3&gt;

&lt;p&gt;Simply run &lt;strong&gt;dep init&lt;/strong&gt; if &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is installed. You can refer to this post for more information about &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.boatswain.io/post/manage-go-dependencies-using-dep/" rel="noopener noreferrer"&gt;Manage Go dependencies using dep&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Or run &lt;strong&gt;go get github.com/labstack/echo&lt;/strong&gt; to download the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; package in &lt;em&gt;$GOPATH&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the hello world
&lt;/h3&gt;

&lt;p&gt;Start the application by &lt;strong&gt;go run main.go&lt;/strong&gt; and then visit &lt;a href="http://localhost:1323" rel="noopener noreferrer"&gt;http://localhost:1323&lt;/a&gt; thru browser or the &lt;strong&gt;curl&lt;/strong&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvus8ov7bjm3eaadn8z1l.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvus8ov7bjm3eaadn8z1l.jpg" alt="Start the Echo server." width="800" height="326"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxh9rssmopfq0laol4cr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyxh9rssmopfq0laol4cr.jpg" alt="Send a request and get the hello world." width="800" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Return a JSON response
&lt;/h2&gt;

&lt;p&gt;When building a RESTful API, it is more likely that the client wants to receive and JSON response instead of a string. Let's write some &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; code in &lt;em&gt;main.go&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{ "id": "1", "msg": "Hello, Boatswain!" }`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Return an HTML
&lt;/h2&gt;

&lt;p&gt;Similar to returning a JSON object, we just need to call another method in the &lt;strong&gt;return&lt;/strong&gt; statement.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, World!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSONBlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`{ "id": "1", "msg": "Hello, Boatswain!" }`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="s"&gt;"&amp;lt;h1&amp;gt;Hello, Boatswain!&amp;lt;/h1&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above are just two simple examples, &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; has a few more convenient ways to return JSON and HTML. For details please refer to the &lt;a href="https://echo.labstack.com/guide/response" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Render HTML using template engine
&lt;/h3&gt;

&lt;p&gt;As mentioned at the very beginning, we could implement template engine when returning the HTTP response but before that, let's restructure the project as follow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;golang-echo-template-example/
  ├── handler/             &lt;span class="c"&gt;# folder of request handlers&lt;/span&gt;
  │   └── home_handler.go
  ├── vendor/              &lt;span class="c"&gt;# dependencies managed by dep&lt;/span&gt;
  │   ├── github.com/&lt;span class="k"&gt;*&lt;/span&gt;
  │   └── golang.org/&lt;span class="k"&gt;*&lt;/span&gt;
  ├── view/                &lt;span class="c"&gt;# folder of html templates&lt;/span&gt;
  │   └── home.html
  ├── Gopkg.lock           &lt;span class="c"&gt;# dep config file&lt;/span&gt;
  ├── Gopkg.toml           &lt;span class="c"&gt;# dep config file&lt;/span&gt;
  └── main.go              &lt;span class="c"&gt;# programme entrypoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"html/template"&lt;/span&gt;
  &lt;span class="s"&gt;"io"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;

  &lt;span class="s"&gt;"gitlab.com/ykyuen/golang-echo-template-example/handler"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Define the template registry struct&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;TemplateRegistry&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Implement e.Renderer interface&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Echo instance&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Instantiate a template registry and register all html files inside the view folder&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseGlob&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/*.html"&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Route =&amp;gt; handler&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HomeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Start the Echo server&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&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;In this &lt;em&gt;main.go&lt;/em&gt;, we define a type called &lt;strong&gt;TemplateRegistry&lt;/strong&gt; and implement the &lt;strong&gt;&lt;a href="https://godoc.org/github.com/labstack/echo#Renderer" rel="noopener noreferrer"&gt;Renderer&lt;/a&gt;&lt;/strong&gt; interface. A &lt;strong&gt;Renderer&lt;/strong&gt; is a simple interface which wraps the &lt;strong&gt;Render()&lt;/strong&gt; function. Inside a &lt;strong&gt;TemplateRegistry&lt;/strong&gt; instance, it has a &lt;strong&gt;templates&lt;/strong&gt; field containing all the templates needed for the &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; server to render html response and this is configured in the &lt;strong&gt;main()&lt;/strong&gt; flow.&lt;/p&gt;

&lt;p&gt;On the other hand, we define the &lt;strong&gt;HomeHandler&lt;/strong&gt; in order to keep the logic in separate file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;handler/home_handler.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HomeHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Please note the the second parameter "home.html" is the template name and should&lt;/span&gt;
  &lt;span class="c"&gt;// be equal to the value stated in the {{ define }} statement in "view/home.html"&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"home.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
    &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"HOME"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"msg"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Hello, Boatswain!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the &lt;strong&gt;c.Render()&lt;/strong&gt; is invoked, it executes the template which is already set in our &lt;strong&gt;TemplateRegistry&lt;/strong&gt; instance as stated in &lt;strong&gt;main.go&lt;/strong&gt;. The three paramaters are&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HTTP response code&lt;/li&gt;
&lt;li&gt;The template name&lt;/li&gt;
&lt;li&gt;The data object which could be used in the template&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;view/home.html&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "home.html"}}
  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&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;title&amp;gt;&lt;/span&gt;Boatswain Blog | {{index . "name"}}&lt;span class="nt"&gt;&amp;lt;/title&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;h1&amp;gt;&lt;/span&gt;{{index . "msg"}}&lt;span class="nt"&gt;&amp;lt;/h1&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;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This above template is named as &lt;strong&gt;home.html&lt;/strong&gt; as stated in the &lt;strong&gt;define&lt;/strong&gt; statement and it could read the &lt;strong&gt;name&lt;/strong&gt; and &lt;strong&gt;msg&lt;/strong&gt; strings from &lt;strong&gt;c.Render()&lt;/strong&gt; for the &lt;strong&gt;&amp;lt;title&amp;gt;&lt;/strong&gt; and &lt;strong&gt;&amp;lt;h1&amp;gt;&lt;/strong&gt; tags.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using nested template
&lt;/h3&gt;

&lt;p&gt;In the above setup, every HTML template has a complete set of HTML code and many of them are duplicated. Using nested template makes it easier to maintain the project. Originally the &lt;strong&gt;templates&lt;/strong&gt; field in the &lt;strong&gt;TemplateRegistry&lt;/strong&gt; contains all the templates files. In the new setup, we make it into an &lt;strong&gt;map&lt;/strong&gt; field and each item is a single set of template files for a particular HTML page.&lt;/p&gt;

&lt;p&gt;We add a few files to the project and it should look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;golang-echo-template-example/
  ├── handler/              &lt;span class="c"&gt;# folder of request handlers&lt;/span&gt;
  │   ├── home_handler.go   &lt;span class="c"&gt;# handler for home page&lt;/span&gt;
  │   └── about_handler.go  &lt;span class="c"&gt;# handler for about page&lt;/span&gt;
  ├── vendor/               &lt;span class="c"&gt;# dependencies managed by dep&lt;/span&gt;
  │   ├── github.com/&lt;span class="k"&gt;*&lt;/span&gt;
  │   └── golang.org/&lt;span class="k"&gt;*&lt;/span&gt;
  ├── view/                 &lt;span class="c"&gt;# folder of html templates&lt;/span&gt;
  │   ├── base.html         &lt;span class="c"&gt;# base layout template&lt;/span&gt;
  │   ├── home.html         &lt;span class="c"&gt;# home page template&lt;/span&gt;
  │   └── about.html        &lt;span class="c"&gt;# about page template&lt;/span&gt;
  ├── Gopkg.lock            &lt;span class="c"&gt;# dep config file&lt;/span&gt;
  ├── Gopkg.toml            &lt;span class="c"&gt;# dep config file&lt;/span&gt;
  └── main.go               &lt;span class="c"&gt;# programme entrypoint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The codes below are based on this &lt;a href="https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678" rel="noopener noreferrer"&gt;gist&lt;/a&gt; created by &lt;a href="https://gist.github.com/rand99" rel="noopener noreferrer"&gt;rand99&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"errors"&lt;/span&gt;
  &lt;span class="s"&gt;"html/template"&lt;/span&gt;
  &lt;span class="s"&gt;"io"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;

  &lt;span class="s"&gt;"gitlab.com/ykyuen/golang-echo-template-example/handler"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Define the template registry struct&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;TemplateRegistry&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Implement e.Renderer interface&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Template not found -&amp;gt; "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ExecuteTemplate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"base.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Echo instance&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c"&gt;// Instantiate a template registry with an array of template set&lt;/span&gt;
  &lt;span class="c"&gt;// Ref: https://gist.github.com/rand99/808e6e9702c00ce64803d94abff65678&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Template&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"home.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/home.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"about.html"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Must&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;template&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ParseFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"view/about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"view/base.html"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Renderer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;TemplateRegistry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c"&gt;// Route =&amp;gt; handler&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HomeHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/about"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AboutHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c"&gt;// Start the Echo server&lt;/span&gt;
  &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":1323"&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 add a new route &lt;strong&gt;/about&lt;/strong&gt; which is handled by a &lt;strong&gt;AboutHandler&lt;/strong&gt; and as you can see from the above highlighted lines, the &lt;strong&gt;templates&lt;/strong&gt; map contains different set of template files for different HTML pages and the &lt;strong&gt;Render()&lt;/strong&gt; takes the &lt;strong&gt;name&lt;/strong&gt; parameter as the &lt;strong&gt;templates&lt;/strong&gt; map key so it could execute the correct template set.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;view/base.html&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "base.html"}}
  &lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;html&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;title&amp;gt;&lt;/span&gt;{{template "title" .}}&lt;span class="nt"&gt;&amp;lt;/title&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;
      {{template "body" .}}
    &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;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;strong&gt;template&lt;/strong&gt; statement tells the template engine that it should look for the &lt;code&gt;{{title}}&lt;/code&gt; and &lt;code&gt;{{body}}&lt;/code&gt; definitions in the template set and they are defined in the &lt;strong&gt;home.html&lt;/strong&gt; and &lt;strong&gt;about.html&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;view/about.html&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{define "title"}}
  Boatswain Blog | {{index . "name"}}
{{end}}

{{define "body"}}
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;{{index . "msg"}}&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;This is the about page.&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
{{end}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is the &lt;strong&gt;AboutHanlder&lt;/strong&gt; which has no big difference from the &lt;strong&gt;HomeHandler&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;handler/about_handler.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"net/http"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/labstack/echo"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;AboutHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="n"&gt;echo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Please note the the second parameter "about.html" is the template name and should&lt;/span&gt;
  &lt;span class="c"&gt;// be equal to one of the keys in the TemplateRegistry array defined in main.go&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"about.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
    &lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"About"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;"msg"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"All about Boatswain!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;This is just a basic example implementing nested template using the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; standard &lt;a href="https://godoc.org/html/template" rel="noopener noreferrer"&gt;html/template&lt;/a&gt; library in &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt;. With proper setup, we could develop a more customized and convenient pattern for &lt;a href="https://echo.labstack.com/" rel="noopener noreferrer"&gt;Echo&lt;/a&gt; or even make it works with any other template engine.&lt;/p&gt;

&lt;p&gt;The complete example could be found on &lt;a href="https://gitlab.com/ykyuen/golang-echo-template-example" rel="noopener noreferrer"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>go</category>
      <category>echo</category>
    </item>
    <item>
      <title>How to setup log rotation for Docker container</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Thu, 14 Jun 2018 03:45:41 +0000</pubDate>
      <link>https://forem.com/ykyuen/how-to-setup-log-rotation-for-docker-container-4alp</link>
      <guid>https://forem.com/ykyuen/how-to-setup-log-rotation-for-docker-container-4alp</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/docker-container-log-rotation/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  We all need logs!
&lt;/h2&gt;

&lt;p&gt;Sometimes working with &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; makes me feel like working with a black box especially when playing with the &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; image from by the community and it doesn't go the way as expected. In many cases, reading logs takes up a large portion of time for debugging.&lt;/p&gt;

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

&lt;p&gt;This article is about setting up log rotation for &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; containers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The default logging driver
&lt;/h2&gt;

&lt;p&gt;We could configure different logging driver for containers and by default the &lt;strong&gt;stdout&lt;/strong&gt; and &lt;strong&gt;stderr&lt;/strong&gt; of the container are written in a json file located in &lt;em&gt;/var/lib/docker/containers/[container-id]/[container-id]-json.log&lt;/em&gt;. If you leave it unattended, it could takes up a large amount of disk space as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firzvr6qf9lyyood5v9qg.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firzvr6qf9lyyood5v9qg.jpg" alt="A large log file in json format" width="800" height="194"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Purge the log manually
&lt;/h3&gt;

&lt;p&gt;In case this json log file takes up a significant amount of the disk, we could purge it using the following command.&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;truncate&lt;/span&gt; &lt;span class="nt"&gt;-s&lt;/span&gt; 0 &amp;lt;logfile&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could setup a cronjob to purge these json log files regularly but for long term, it would be better to setup log rotation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup the log rotation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configure the default logging driver
&lt;/h3&gt;

&lt;p&gt;This could be done by adding the following values in &lt;em&gt;/etc/docker/daemon.json&lt;/em&gt;. Create this file if it doesn't exist.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"log-driver"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json-file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"log-opts"&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;"max-size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10m"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"max-file"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;json-file&lt;/em&gt; logging driver has a few more options and we could even change to other logging drivers such as &lt;em&gt;syslog&lt;/em&gt;. For more information, please refer to the &lt;a href="https://docs.docker.com/config/containers/logging/configure/" rel="noopener noreferrer"&gt;Docker Docs - Configure logging drivers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Execute the following commands to reload the updated &lt;em&gt;daemon.json&lt;/em&gt;. The new configuration will apply to all newly created container after restart.&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="nv"&gt;$ &lt;/span&gt;systemctl daemon-reload

&lt;span class="nv"&gt;$ &lt;/span&gt;systemctl restart docker
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure the logging driver for a container
&lt;/h3&gt;

&lt;p&gt;The configuration could also be done on container level if you do not want to apply it globally.&lt;/p&gt;

&lt;h4&gt;
  
  
  The docker run command
&lt;/h4&gt;

&lt;p&gt;We could specify the logging driver and options in the &lt;em&gt;docker run&lt;/em&gt; command. For example:&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="nv"&gt;$ &lt;/span&gt;docker run &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--log-driver&lt;/span&gt; json-file &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--log-opt&lt;/span&gt; max-size&lt;span class="o"&gt;=&lt;/span&gt;10m &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--log-opt&lt;/span&gt; max-file&lt;span class="o"&gt;=&lt;/span&gt;10 &lt;span class="se"&gt;\&lt;/span&gt;
    alpine &lt;span class="nb"&gt;echo &lt;/span&gt;hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Using docker-compose
&lt;/h4&gt;

&lt;p&gt;The logging driver and options could also be configured using docker-compose. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.2'&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;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nginx:latest'&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;80:80'&lt;/span&gt;
    &lt;span class="na"&gt;logging&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;driver&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;json-file"&lt;/span&gt;
      &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;max-size&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;1k"&lt;/span&gt;
        &lt;span class="na"&gt;max-file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify if the setup is working.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p9tfpdb6koy07qvg1mr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p9tfpdb6koy07qvg1mr.jpg" alt="The logs are broken down into 1k files" width="800" height="227"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Although the default setting works fine, you never know when the container logs take up all the disk space and that could be avoided by the above few steps. Other than that, logs are important asset which is not only useful when something goes wrong but also contains a lot of hidden values. So never never let the logs go.&lt;/p&gt;

&lt;p&gt;If you are looking for a &lt;strong&gt;log management SAAS solution&lt;/strong&gt;, consider using &lt;a href="https://boatswain.io/" rel="noopener noreferrer"&gt;Boatswain&lt;/a&gt; and we help you managing all the logs as well as monitoring your &lt;a href="https://www.docker.com/" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; servers. 💫&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuks2gcmbt4pbwpugncj9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuks2gcmbt4pbwpugncj9.jpg" alt="Insufficient facts always invite danger" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Insufficient facts always invite danger.&lt;br&gt;
-- Spock @ Star Trek&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>docker</category>
      <category>logging</category>
    </item>
    <item>
      <title>Driving web browser in Go</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Fri, 09 Mar 2018 02:02:45 +0000</pubDate>
      <link>https://forem.com/ykyuen/driving-web-browser-in-go--53de</link>
      <guid>https://forem.com/ykyuen/driving-web-browser-in-go--53de</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/driving-web-browser-in-go/"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;This article is about driving web browser in &lt;a href="https://golang.org/"&gt;Golang&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Agouti
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; is an acceptance and testing framework. It could be used together with &lt;a href="http://onsi.github.io/ginkgo/"&gt;Ginkgo&lt;/a&gt; which is a BDD testing framework and &lt;a href="http://onsi.github.io/gomega/"&gt;Gomega&lt;/a&gt; matcher/assertion library if you are looking for a complete testing solution for your &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; project.&lt;/p&gt;

&lt;p&gt;The following example only make use of &lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; to drive a browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the project inside $GOPATH
&lt;/h2&gt;

&lt;p&gt;Create the &lt;em&gt;main.go&lt;/em&gt; under &lt;em&gt;$GOPATH/src/gitlab.com/ykyuen/driving-web-browser-in-go-example&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"log"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/sclevine/agouti"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// driver := agouti.PhantomJS()&lt;/span&gt;
  &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;agouti&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChromeDriver&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="c"&gt;// driver := agouti.ChromeDriver(&lt;/span&gt;
  &lt;span class="c"&gt;//   agouti.ChromeOptions("args", []string{"--headless", "--disable-gpu", "--no-sandbox"}),&lt;/span&gt;
  &lt;span class="c"&gt;// )&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to start driver:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to open page:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://agouti.org/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to navigate:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;sectionTitle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FindByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`getting-agouti`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sectionTitle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;driver&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to close pages and stop WebDriver:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; supports web drivers such as &lt;a href="http://phantomjs.org/"&gt;PhantomJS&lt;/a&gt;, &lt;a href="http://www.seleniumhq.org/"&gt;Selenium&lt;/a&gt; and &lt;a href="https://www.google.com/chrome/"&gt;Chrome&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download the Go dependency
&lt;/h3&gt;

&lt;p&gt;Let's use &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt; to manage the &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; dependency. Simply run the &lt;em&gt;dep init&lt;/em&gt; command.&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="o"&gt;[&lt;/span&gt;ykyuen@camus driving-web-browser-in-go-example]&lt;span class="nv"&gt;$ &lt;/span&gt;dep init
  Using ^2.0.0 as constraint &lt;span class="k"&gt;for &lt;/span&gt;direct dep github.com/sclevine/agouti
  Locking &lt;span class="k"&gt;in &lt;/span&gt;v2.0 &lt;span class="o"&gt;(&lt;/span&gt;b920a9c&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;direct dep github.com/sclevine/agouti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the moment when i am writing this article. The default downloaded version of &lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; by &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt; is too old. Let's update it to the latest master manually.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gopkg.toml&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[[constraint]]&lt;/span&gt;
  &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"github.com/sclevine/agouti"&lt;/span&gt;
  &lt;span class="py"&gt;branch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"master"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;em&gt;dep ensure&lt;/em&gt; to update &lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run the code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;ykyuen@camus driving-web-browser-in-go-example]&lt;span class="nv"&gt;$ &lt;/span&gt;go run main.go
2018/01/21 19:02:42 Getting Agouti
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are using ChromeDriver, you should be able to see the &lt;a href="https://www.google.com/chrome/"&gt;Chrome&lt;/a&gt; browser will be started automatically and execute the tasks as stated in &lt;em&gt;main.go&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running in headless browser
&lt;/h2&gt;

&lt;p&gt;We could also run the code in headless browsers like &lt;a href="http://phantomjs.org/"&gt;PhantomJS&lt;/a&gt;. &lt;a href="https://www.google.com/chrome/"&gt;Chrome&lt;/a&gt; also supports headless mode. Let's update the code as follow.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;main.go&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="s"&gt;"log"&lt;/span&gt;

  &lt;span class="s"&gt;"github.com/sclevine/agouti"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// driver := agouti.PhantomJS()&lt;/span&gt;
  &lt;span class="c"&gt;// driver := agouti.ChromeDriver()&lt;/span&gt;
  &lt;span class="n"&gt;driver&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;agouti&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChromeDriver&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;agouti&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ChromeOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"--headless"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--disable-gpu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"--no-sandbox"&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could still get the title from the &lt;a href="https://agouti.org/"&gt;Agouti&lt;/a&gt; website without starting the &lt;a href="https://www.google.com/chrome/"&gt;Chrome&lt;/a&gt; window.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;This example is not about writing test case but just showing how to drive a web browser.&lt;/li&gt;
&lt;li&gt;For testing, we probably need &lt;a href="http://onsi.github.io/ginkgo/"&gt;Ginkgo&lt;/a&gt; and &lt;a href="http://onsi.github.io/gomega/"&gt;Gomega&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I also tried another &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; package called &lt;a href="https://github.com/chromedp/chromedp"&gt;chromedp&lt;/a&gt; but it doesn't work well.

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/chromedp/chromedp/issues/115"&gt;chromedp used as a functional test tool?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/chromedp/chromedp/issues/167"&gt;Saving screenshot with headless chrome throws "invalid image size" error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/chromedp/chromedp/issues/70"&gt;Click does not work in a specific environment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Complete example is available at &lt;a href="https://gitlab.com/ykyuen/driving-web-browser-in-go-example"&gt;gitlab.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>agouti</category>
    </item>
    <item>
      <title>Web UI Testing in NodeJS</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Wed, 28 Feb 2018 16:37:20 +0000</pubDate>
      <link>https://forem.com/ykyuen/web-ui-testing-in-nodejs--kda</link>
      <guid>https://forem.com/ykyuen/web-ui-testing-in-nodejs--kda</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/web-ui-testing-in-nodejs/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




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

&lt;p&gt;In this article i would like to demonstrate some tools in &lt;a href="http://nodejs.org/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; for testing web UI. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;Mocha&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://chaijs.com/" rel="noopener noreferrer"&gt;Chai&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://phantomjs.org/" rel="noopener noreferrer"&gt;PhantomJS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Mocha
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://mochajs.org/" rel="noopener noreferrer"&gt;Mocha&lt;/a&gt; is a Javascript framework for testing. It has a &lt;em&gt;BDD-style&lt;/em&gt; syntax &lt;strong&gt;(BDD: &lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development" rel="noopener noreferrer"&gt;Behavior-driven development&lt;/a&gt;)&lt;/strong&gt; and allows asychronous call testing. It also supports different assertion libraries and in our exampe we will use &lt;a href="http://chaijs.com/" rel="noopener noreferrer"&gt;chai&lt;/a&gt; for assertion.&lt;/p&gt;

&lt;h4&gt;
  
  
  Chai
&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://chaijs.com/" rel="noopener noreferrer"&gt;Chai&lt;/a&gt; is a &lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development" rel="noopener noreferrer"&gt;BDD&lt;/a&gt;/&lt;a href="https://en.wikipedia.org/wiki/Test-driven_development" rel="noopener noreferrer"&gt;TDD&lt;/a&gt; assertion library for &lt;a href="http://nodejs.org/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; and the browser that can be delightfully paired with any Javascript testing framework.&lt;/p&gt;

&lt;h4&gt;
  
  
  CasperJS
&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt; is a helper library for building navigation scenarios. It is often used with &lt;a href="http://phantomjs.org/" rel="noopener noreferrer"&gt;PhantomJS&lt;/a&gt; but actually it also supports &lt;a href="https://slimerjs.org/" rel="noopener noreferrer"&gt;SlimerJS&lt;/a&gt; which is another headless browser with the &lt;a href="https://www.mozilla.org/" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt; rendering engine called &lt;a href="http://geckoisgecko.org/" rel="noopener noreferrer"&gt;Gecko&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  PhantomJS
&lt;/h4&gt;

&lt;p&gt;&lt;a href="http://phantomjs.org/" rel="noopener noreferrer"&gt;PhantomJS&lt;/a&gt; is a headless browser with the &lt;a href="https://webkit.org/" rel="noopener noreferrer"&gt;WebKit&lt;/a&gt; rendering engine. It allows running browser-based tests in a headless system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Check if the Google search is working
&lt;/h2&gt;

&lt;p&gt;Let's get started with a simple example. Assume we would like to test the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Is the Google search page accessible?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Is the search function able to return a list of result?&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the first question, we could simple make a HTTP request to the Google URL and see if it returns a HTTP 200 response code and this could be done easily by &lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The second question is a bit more complicated. It could be broken down into the following steps.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Wait for the search form&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fill in the form and submit&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Check if the result set contains the search text&lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let's go through the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initialize a new NodeJS project
&lt;/h3&gt;



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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install the following node modules
&lt;/h3&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;casperjs chai mocha phantomjs &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;span class="c"&gt;# In addition to the above libraries, we also need the following extensions.&lt;/span&gt;
npm &lt;span class="nb"&gt;install &lt;/span&gt;casper-chai mocha-casperjs &lt;span class="nt"&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Setup the tests
&lt;/h3&gt;

&lt;p&gt;Create the &lt;em&gt;test/google-search.js&lt;/em&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="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Google Search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Before script for each test&lt;/span&gt;
  &lt;span class="nf"&gt;before&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.google.com.hk/&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="c1"&gt;// *** Test 1 ***&lt;/span&gt;
  &lt;span class="c1"&gt;// Is the Google search page accessible?&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should have return HTTP 200&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentHTTPStatus&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// *** Test 2 ***&lt;/span&gt;
  &lt;span class="c1"&gt;// Is the search function able to return a list of result?&lt;/span&gt;
  &lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should be able to search&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Wait for the search form&lt;/span&gt;
    &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form[action="/search"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form[action="/search"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;should&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inDOM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Fill in the form and submit&lt;/span&gt;
    &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form[action="/search"]&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="na"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Boatswain&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Check if the result set contains text "Boatswain"&lt;/span&gt;
    &lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;should&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inDOM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/Boatswain/&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a npm script for running the test
&lt;/h3&gt;

&lt;p&gt;Edit the &lt;em&gt;package.json&lt;/em&gt; as follow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="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;"ui-test"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.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;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"test"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mocha-casperjs test/google-search.js"&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;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ykyuen"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"license"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ISC"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&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;"casper-chai"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.3.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;"casperjs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.1.4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"chai"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.1.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"mocha"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.1.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;"mocha-casperjs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^0.6.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;"phantomjs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^2.1.7"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run the test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm9056dkoqbqpwnzqinf.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqm9056dkoqbqpwnzqinf.jpg" alt="Test passed!" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Test passed! ✅&lt;/center&gt;

&lt;p&gt;A brief test report will be shown after the test run has finished.&lt;/p&gt;

&lt;h3&gt;
  
  
  Let's try to fail the test
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Check if the result set contains text "Boatswain"&lt;/span&gt;
&lt;span class="nx"&gt;casper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;should&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;be&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inDOM&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;h3.r a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/nosuchtext/&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;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l5ichqp16kafhw4f3ge.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l5ichqp16kafhw4f3ge.jpg" alt="Test failed!" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;Test failed! ❌&lt;/center&gt;

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

&lt;p&gt;This example shows how to create a simple web UI test in &lt;a href="http://nodejs.org/" rel="noopener noreferrer"&gt;NodeJS&lt;/a&gt; and execute the test in command line prompt. It could be used in &lt;a href="https://en.wikipedia.org/wiki/Smoke_testing_(software)" rel="noopener noreferrer"&gt;smoke testing&lt;/a&gt; for staging environment. Please also note that &lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt; is &lt;strong&gt;NOT&lt;/strong&gt; for unit testing but rather web UI testing. In addition, test runner like &lt;a href="https://karma-runner.github.io" rel="noopener noreferrer"&gt;Karma&lt;/a&gt; does not support &lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt;. If you are looking for unit testing solution, you should probably rule out &lt;a href="http://casperjs.org/" rel="noopener noreferrer"&gt;CasperJS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Complete example is available on &lt;a href="https://gitlab.com/ykyuen/glide-example" rel="noopener noreferrer"&gt;gitlab.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>mocha</category>
      <category>casperjs</category>
      <category>phantomjs</category>
    </item>
    <item>
      <title>Manage Go dependencies using dep</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Tue, 23 Jan 2018 01:49:38 +0000</pubDate>
      <link>https://forem.com/ykyuen/manage-go-dependencies-using-dep-16p9</link>
      <guid>https://forem.com/ykyuen/manage-go-dependencies-using-dep-16p9</guid>
      <description>&lt;h2&gt;
  
  
  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fwhm3oezk396jxn6di1h6.png" alt="dep — A Go dependency management tool"&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Update @ 2018-11-26: Technology is not just moving at a breakneck speed but also changing rapidly. Within a year, this article is OUTDATED!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1066473266020261888-542" src="https://platform.twitter.com/embed/Tweet.html?id=1066473266020261888"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1066473266020261888-542');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1066473266020261888&amp;amp;theme=dark"
  }



&lt;/p&gt;

&lt;p&gt;And according to the &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep project page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;dep was the "official experiment." The Go toolchain, as of 1.11, has (experimentally) adopted an approach that sharply diverges from dep. As a result, we are continuing development of dep, but gearing work primarily towards the development of an alternative prototype for versioning behavior in the toolchain.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more information about the new Go build-in management, please refer to the official GitHub Wiki - &lt;a href="https://github.com/golang/go/wiki/Modules" rel="noopener noreferrer"&gt;Go 1.11 Modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks &lt;a href="https://twitter.com/bitfield" rel="noopener noreferrer"&gt;John Arundel @bitfield&lt;/a&gt; and &lt;a href="https://twitter.com/yakuter" rel="noopener noreferrer"&gt;Erhan Yakut @yakuter&lt;/a&gt; for revealing the problem. 🙇🏽‍♂️&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Update @ 2018-02-03: &lt;a href="https://github.com/sdboyer" rel="noopener noreferrer"&gt;Sam Boyer&lt;/a&gt; from the godep team has clarified some incorrect information in this article. I apologize to &lt;a href="https://github.com/sdboyer" rel="noopener noreferrer"&gt;Sam Boyer&lt;/a&gt; and the readers for any inconvenience.&lt;/strong&gt; 😢&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/manage-go-dependencies-using-dep/" rel="noopener noreferrer"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Previously i posted an &lt;a href="https://blog.boatswain.io/post/manage-go-dependencies-using-glide/" rel="noopener noreferrer"&gt;article&lt;/a&gt; about dependency management in &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Go&lt;/a&gt; using &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; and i got a feedback about &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; will become obsolete and the &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; team is suggesting users moving to a another dependency management tool called &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; written by the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;golang&lt;/a&gt; team.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Go community now has the dep project to manage dependencies. Please consider trying to migrate from Glide to dep... Glide will continue to be supported for some time but is considered to be in a state of support rather than active feature development.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There is a plan about integrating &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; into the toolchain in &lt;a href="https://tip.golang.org/doc/go1.10" rel="noopener noreferrer"&gt;Go 1.10 release&lt;/a&gt; but seems &lt;a href="https://www.reddit.com/r/golang/comments/7dd2ty/go_110_release_notes_draft/#thing_t1_dpwyj4i" rel="noopener noreferrer"&gt;it still has a way to go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update @ 2018-02-03:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is officially released.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is not moving into the toolchain with 1.10. please refer to the &lt;a href="https://github.com/golang/dep/wiki/Roadmap" rel="noopener noreferrer"&gt;roadmap&lt;/a&gt; for the latest information.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkghqq76vmqrkz019hkob.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fkghqq76vmqrkz019hkob.jpg" alt="Technology is moving too fast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  And i am just not fast enough. 🐌
&lt;/h5&gt;

&lt;h2&gt;
  
  
  Create the project inside $GOPATH
&lt;/h2&gt;

&lt;p&gt;Same as before, let's create a new project with root path &lt;em&gt;$GOPATH/src/gitlab.com/ykyuen/dep-example&lt;/em&gt; and add the following file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt; &lt;span class="s"&gt;"github.com/dustin/go-humanize"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"That file is %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;82854982&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// That file is 83 MB.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You're my %s best friend.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;193&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You are my 193rd best friend.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You owe $%s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6582491&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You owe $6,582,491.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The dep way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Gopkg.toml and Gopkg.lock
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; reads two files called &lt;em&gt;Gopkg.toml&lt;/em&gt; and the &lt;em&gt;Gopkg.lock&lt;/em&gt;. Let's initialize these 2 files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus dep-example]$ dep init
  Using master as constraint for direct dep github.com/dustin/go-humanize
  Locking in master (bb3d318) for direct dep github.com/dustin/go-humanize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;em&gt;dep init&lt;/em&gt; command scans the source codes and downloads all the packages needed for the project into the &lt;em&gt;vendor&lt;/em&gt; folder.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Gopkg.lock&lt;/em&gt; serves exactly the same function as the &lt;em&gt;glide.lock&lt;/em&gt; file which locks the version of the packages &lt;strong&gt;EXCEPT&lt;/strong&gt; the version should be maintained in the &lt;em&gt;Gopkg.toml&lt;/em&gt;. In short, the &lt;em&gt;Gopkg.lock&lt;/em&gt; file is auto-generated and it depends on the &lt;em&gt;import&lt;/em&gt; statements in the source with version controlled by &lt;em&gt;Gopkg.toml&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F76aglpqie9q1kx22ft78.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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2F76aglpqie9q1kx22ft78.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Update dependency’s version
&lt;/h3&gt;

&lt;p&gt;Let's edit the &lt;em&gt;Gopkg.toml&lt;/em&gt; and use a slightly older version of the &lt;a href="https://github.com/dustin/go-humanize" rel="noopener noreferrer"&gt;go-humanize&lt;/a&gt; package instead of the latest master branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Gopkg.toml example&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md&lt;/span&gt;
&lt;span class="c"&gt;# for detailed Gopkg.toml documentation.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# required = ["github.com/user/thing/cmd/thing"]&lt;/span&gt;
&lt;span class="c"&gt;# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# [[constraint]]&lt;/span&gt;
&lt;span class="c"&gt;#   name = "github.com/user/project"&lt;/span&gt;
&lt;span class="c"&gt;#   version = "1.0.0"&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# [[constraint]]&lt;/span&gt;
&lt;span class="c"&gt;#   name = "github.com/user/project2"&lt;/span&gt;
&lt;span class="c"&gt;#   branch = "dev"&lt;/span&gt;
&lt;span class="c"&gt;#   source = "github.com/myfork/project2"&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# [[override]]&lt;/span&gt;
&lt;span class="c"&gt;#  name = "github.com/x/y"&lt;/span&gt;
&lt;span class="c"&gt;#  version = "2.4.0"&lt;/span&gt;


&lt;span class="nn"&gt;[[constraint]]&lt;/span&gt;
  &lt;span class="c"&gt;#branch = "master"&lt;/span&gt;
  &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"github.com/dustin/go-humanize"&lt;/span&gt;
  &lt;span class="py"&gt;revision&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0b19b17f90333e44518aa31bbf8126017960aee3"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;em&gt;dep ensure&lt;/em&gt; to update the package to the desired version. The following is the diff of the updated &lt;em&gt;Gopkg.lock&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;--- /home/ykyuen/go/src/gitlab.com/ykyuen/dep-example/Gopkg.lock
&lt;/span&gt;&lt;span class="gi"&gt;+++ # This file is autogenerated, do not edit; changes
&lt;/span&gt;&lt;span class="p"&gt;@@ -2,14 +2,13 @@&lt;/span&gt;
&lt;span class="err"&gt;

&lt;/span&gt; [[projects]]
&lt;span class="gd"&gt;-  branch = "master"
&lt;/span&gt;   name = "github.com/dustin/go-humanize"
   packages = ["."]
&lt;span class="gd"&gt;-  revision = "bb3d318650d48840a39aa21a027c6630e198e626"
&lt;/span&gt;&lt;span class="gi"&gt;+  revision = "0b19b17f90333e44518aa31bbf8126017960aee3"
&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt; [solve-meta]
   analyzer-name = "dep"
   analyzer-version = 1
&lt;span class="gd"&gt;-  inputs-digest = "a5d65a2bdf47e41b99ad71813142ae93970f5806c77630b2aea665fe631dde23"
&lt;/span&gt;&lt;span class="gi"&gt;+  inputs-digest = "0023bfe634a061b89ae0fbd71e3236f3f75f0843a0c974eeb9822040c0ea2dc4"
&lt;/span&gt;   solver-name = "gps-cdcl"
   solver-version = 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Add a new dependency
&lt;/h3&gt;

&lt;p&gt;New package could be added using the &lt;em&gt;dep ensure -add&lt;/em&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus dep-example]$ dep ensure -add github.com/leekchan/accounting
Fetching sources...

"github.com/leekchan/accounting" is not imported by your project, and has been temporarily added to Gopkg.lock and vendor/.
If you run "dep ensure" again before actually importing it, it will disappear from Gopkg.lock and vendor/.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we have the new &lt;em&gt;accounting&lt;/em&gt; package ready in the &lt;em&gt;vendor&lt;/em&gt; folder with new constraints written to &lt;em&gt;Gopkg.toml&lt;/em&gt; and locked in &lt;em&gt;Gopkg.lock&lt;/em&gt;. Let's update the &lt;em&gt;main.go&lt;/em&gt; as follow.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt; &lt;span class="s"&gt;"github.com/dustin/go-humanize"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;accounting&lt;/span&gt; &lt;span class="s"&gt;"github.com/leekchan/accounting"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"math/big"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"That file is %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;82854982&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// That file is 83 MB.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You're my %s best friend.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;193&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You are my 193rd best friend.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You owe $%s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6582491&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You owe $6,582,491.&lt;/span&gt;

  &lt;span class="n"&gt;ac&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;accounting&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accounting&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Symbol&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"$"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Precision&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatMoney&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123456789.213123&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;                       &lt;span class="c"&gt;// "$123,456,789.21"&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatMoney&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;12345678&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;                               &lt;span class="c"&gt;// "$12,345,678.00"&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatMoney&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;77777777&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;                &lt;span class="c"&gt;// "$25,925,925.67"&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatMoney&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="m"&gt;77777777&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;               &lt;span class="c"&gt;// "-$25,925,925.67"&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FormatMoneyBigFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;big&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123456789.213123&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt; &lt;span class="c"&gt;// "$123,456,789.21"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And run it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus dep-example]$ go run main.go
hello world
That file is 83 MB.
You're my 193rd best friend.
You owe $6,582,491.
$123,456,789.21
$12,345,678.00
$25,925,925.67
-$25,925,925.67
$123,456,789.21
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The issue with git submodule
&lt;/h2&gt;

&lt;p&gt;One major difference of &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; compared to &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; is the package's submodule is ignored. For example, after adding the &lt;a href="https://github.com/go-goracle/goracle" rel="noopener noreferrer"&gt;go-goracle/goracle&lt;/a&gt; package by &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt;, the &lt;a href="https://oracle.github.io/odpi/" rel="noopener noreferrer"&gt;odpi&lt;/a&gt; submodule inside is empty and leads to error. The reason of dropping the submodule could be found in the following link.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/dep/issues/1240" rel="noopener noreferrer"&gt;Are there any plans to add git submodules support ?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Update @ 2018-02-03:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The paragraph about git submodule is incorrect.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/sdboyer" rel="noopener noreferrer"&gt;Sam Boyer&lt;/a&gt; wrote:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;dep should be perfectly fine at pulling in git submodules in the case you describe. I just replicated what you describe here locally, and the problem isn’t submodules — it’s that there’s no Go code in github.com/go-goracle/goracle/odpi, so it can’t be imported directly.&lt;/p&gt;

&lt;p&gt;You likely need to turn off unused-packages pruning in Gopkg.toml for that project specifically, as otherwise dep ensure will automatically remove what appears to be an unused directly (but it seems it’s actually used by cgo).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Update @ 2018-03-04:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It is found that the &lt;a href="https://github.com/go-goracle/goracle" rel="noopener noreferrer"&gt;go-goracle/goracle&lt;/a&gt; package doesn't work with &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt;. You could follow the issue below and check the latest update from the &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; team.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/golang/dep/issues/1633" rel="noopener noreferrer"&gt;Fail to get git submodule of a package after the dep ensure command&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is quite likely to be the official dependency management tool in the &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt; community.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;If you are starting a new &lt;a href="https://golang.org/" rel="noopener noreferrer"&gt;Golang&lt;/a&gt; project, &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is good to go.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;If you are using &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; in a legacy project. You could consider migrating to &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; but i think there is no harm to keep using &lt;a href="https://glide.sh/" rel="noopener noreferrer"&gt;Glide&lt;/a&gt; for a while until &lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is officially released.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;del&gt;In addition, missing package's submodule may result in malfunction of your code.&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; is officially released.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://github.com/golang/dep" rel="noopener noreferrer"&gt;dep&lt;/a&gt; works well on pulling git submodule.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;You can checkout this example on &lt;a href="https://gitlab.com/ykyuen/dep-example" rel="noopener noreferrer"&gt;gitlab.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>dep</category>
      <category>glide</category>
    </item>
    <item>
      <title>Manage Go dependencies using Glide</title>
      <dc:creator>Yuen Ying Kit</dc:creator>
      <pubDate>Tue, 16 Jan 2018 02:46:57 +0000</pubDate>
      <link>https://forem.com/ykyuen/manage-go-dependencies-using-glide-2d7k</link>
      <guid>https://forem.com/ykyuen/manage-go-dependencies-using-glide-2d7k</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://blog.boatswain.io/post/manage-go-dependencies-using-glide/"&gt;Boatswain Blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Update @ 2018-01-17&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You might want to consider using a new dependency management tool called &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt; as suggested by &lt;a href="https://dev.to/nasa9084/comment/2317"&gt;nasa9084&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://glide.sh/"&gt;Glide&lt;/a&gt; is a &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; package management tool, like &lt;a href="https://www.npmjs.com/"&gt;npm&lt;/a&gt; in &lt;a href="https://nodejs.org/en/"&gt;NodeJS&lt;/a&gt;. Let's create a simple example and see how it works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create the project inside $GOPATH
&lt;/h2&gt;

&lt;p&gt;The project folder has to be under &lt;em&gt;$GOPATH&lt;/em&gt; in order to resolve the &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; package paths. In this example, the project root folder is &lt;em&gt;$GOPATH/src/gitlab.com/ykyuen/glide-example&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A hello world Go program
&lt;/h2&gt;

&lt;p&gt;Let's create a simple &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; program.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Build and run
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ go build -o hello
[ykyuen@camus glide-example]$ ./hello
hello world
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a Go dependency
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/dustin/go-humanize"&gt;dustin/go-humanize&lt;/a&gt; is a helpful &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; package to format number, string and time. Let's update our &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; program as follow.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;main.go&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt; &lt;span class="s"&gt;"github.com/dustin/go-humanize"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"fmt"&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello world"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"That file is %s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;82854982&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// That file is 83 MB.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You're my %s best friend.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Ordinal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;193&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You are my 193rd best friend.&lt;/span&gt;
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"You owe $%s.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;humanize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Comma&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;6582491&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="c"&gt;// You owe $6,582,491.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now if we try to build it, it will throws the following error.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ go build -o hello
main.go:3:8: cannot find package "github.com/dustin/go-humanize" in any of:
  /home/ykyuen/tools/go1.8.4/src/github.com/dustin/go-humanize (from $GOROOT)
  /home/ykyuen/go/src/github.com/dustin/go-humanize (from $GOPATH)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because we haven't downloaded the &lt;a href="https://github.com/dustin/go-humanize"&gt;dustin/go-humanize&lt;/a&gt;. Without using &lt;a href="https://glide.sh/"&gt;Glide&lt;/a&gt;, we could solve this build error by running the &lt;em&gt;go get&lt;/em&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go get github.com/dustin/go-humanize
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in this case, anyone who checkouts the project has no idea what packages are needed in order to build the program. If you have already run the &lt;em&gt;go get&lt;/em&gt; command, delete the package before proceeding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Glide way
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create the glide.yaml
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;glide.yaml&lt;/em&gt; could be generated by the &lt;em&gt;glide create&lt;/em&gt; command. It will scan the &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; src files and include all the dependencies needed. Here is the output of this example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ glide create
[INFO]  Generating a YAML configuration file and guessing the dependencies
[INFO]  Attempting to import from other package managers (use --skip-import to skip)
[INFO]  Scanning code to look for dependencies
[INFO]  --&amp;gt; Found reference to github.com/dustin/go-humanize
[INFO]  Writing configuration file (glide.yaml)
[INFO]  Would you like Glide to help you find ways to improve your glide.yaml configuration?
[INFO]  If you want to revisit this step you can use the config-wizard command at any time.
[INFO]  Yes (Y) or No (N)?
Y
[INFO]  Looking for dependencies to make suggestions on
[INFO]  --&amp;gt; Scanning for dependencies not using version ranges
[INFO]  --&amp;gt; Scanning for dependencies using commit ids
[INFO]  Gathering information on each dependency
[INFO]  --&amp;gt; This may take a moment. Especially on a codebase with many dependencies
[INFO]  --&amp;gt; Gathering release information for dependencies
[INFO]  --&amp;gt; Looking for dependency imports where versions are commit ids
[INFO]  No proposed changes found. Have a nice day.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;glide.yaml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gitlab.com/ykyuen/glide-example&lt;/span&gt;
&lt;span class="na"&gt;import&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.com/dustin/go-humanize&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download the Go dependencies to the vendor folder
&lt;/h3&gt;

&lt;p&gt;Next, we execute the &lt;em&gt;glide install&lt;/em&gt; command to download the dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ glide install
[INFO]  Lock file (glide.lock) does not exist. Performing update.
[INFO]  Downloading dependencies. Please wait...
[INFO]  --&amp;gt; Fetching updates for github.com/dustin/go-humanize
[INFO]  Resolving imports
[INFO]  Downloading dependencies. Please wait...
[INFO]  Setting references for remaining imports
[INFO]  Exporting resolved dependencies...
[INFO]  --&amp;gt; Exporting github.com/dustin/go-humanize
[INFO]  Replacing existing vendor dependencies
[INFO]  Project relies on 1 dependencies.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will generated the &lt;em&gt;glide.lock&lt;/em&gt; files and the &lt;em&gt;vendor&lt;/em&gt; folder which contains the &lt;a href="https://github.com/dustin/go-humanize"&gt;dustin/go-humanize&lt;/a&gt; package. The &lt;em&gt;glide.lock&lt;/em&gt; file contains the version of the package. It could be a &lt;strong&gt;tag&lt;/strong&gt; or a &lt;strong&gt;git commit hash&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;glide.lock&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;de8aada0e0453f13dc438db5fb412db797d701d6afeadcc052c477fd55e01aa8&lt;/span&gt;
&lt;span class="na"&gt;updated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2017-12-04T23:20:53.616704682+08:00&lt;/span&gt;
&lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.com/dustin/go-humanize&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8929fe90cee4b2cb9deb468b51fb34eba64d1bf0&lt;/span&gt;
&lt;span class="na"&gt;testImports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update dependency's version
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/dustin/go-humanize/commit/8929fe90cee4b2cb9deb468b51fb34eba64d1bf0"&gt;8929fe9&lt;/a&gt; commit is quite outdated. We could modify version in the &lt;em&gt;glide.lock&lt;/em&gt; file and run &lt;em&gt;glide install&lt;/em&gt; again to get the desired version of your package.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;glide.lock&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;hash&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;de8aada0e0453f13dc438db5fb412db797d701d6afeadcc052c477fd55e01aa8&lt;/span&gt;
&lt;span class="na"&gt;updated&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2017-12-04T23:20:53.616704682+08:00&lt;/span&gt;
&lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.com/dustin/go-humanize&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bb3d318650d48840a39aa21a027c6630e198e626&lt;/span&gt;
&lt;span class="na"&gt;testImports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ glide install
[INFO]  Downloading dependencies. Please wait...
[INFO]  --&amp;gt; Found desired version locally github.com/dustin/go-humanize bb3d318650d48840a39aa21a027c6630e198e626!
[INFO]  Setting references.
[INFO]  --&amp;gt; Setting version for github.com/dustin/go-humanize to bb3d318650d48840a39aa21a027c6630e198e626.
[INFO]  Exporting resolved dependencies...
[INFO]  --&amp;gt; Exporting github.com/dustin/go-humanize
[INFO]  Replacing existing vendor dependencies
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build and run again
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ykyuen@camus glide-example]$ go build -o hello
[ykyuen@camus glide-example]$ ./hello
hello world
That file is 83 MB.
You're my 193rd best friend.
You owe $6,582,491.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Check in the vendor folder?
&lt;/h3&gt;

&lt;p&gt;For &lt;a href="https://nodejs.org/en/"&gt;NodeJS&lt;/a&gt; projects there is a common practice that we will ignore the &lt;em&gt;node_modules&lt;/em&gt; folder in the code repository. On the other hand, the &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; community has a different point of view.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.reddit.com/r/golang/comments/6b9817/should_i_add_vendor_directory_into_gitignore_if_i/"&gt;Should I add "vendor" directory into .gitignore if I am using tools like glide or godep?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There isn't an absolute answer. Pick the option which you feel more comfortable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other concerns
&lt;/h3&gt;

&lt;p&gt;When the project is getting bigger, &lt;a href="https://glide.sh/"&gt;glide&lt;/a&gt; might take quite a while to work as the dependency tree is getting bigger and bigger. In addition, it's hard to manage to the dependency's version.&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://dev.to/nasa9084/comment/2317"&gt;nasa9084&lt;/a&gt; suggested, you might want to consider using a new dependency management tool called &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt; as suggested by the &lt;a href="https://glide.sh/"&gt;Glide&lt;/a&gt; team. &lt;a href="https://github.com/golang/dep"&gt;dep&lt;/a&gt; has a &lt;a href="https://go.libhunt.com/project/dep/vs/glide"&gt;growing popularity and in active development&lt;/a&gt;. Do take a look on the &lt;a href="https://github.com/golang/dep#current-status"&gt;dep's project status&lt;/a&gt; and pick the one which you feel more comfortable.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;Project folder has to be under &lt;em&gt;$GOPATH&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Dependencies would be included automatically by scanning all the source code.&lt;/li&gt;
&lt;li&gt;Dependency's version is managed by &lt;em&gt;glide.lock&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Commit the &lt;em&gt;vendor&lt;/em&gt; folder or not is still an open question.&lt;/li&gt;
&lt;li&gt;Performance issue when dependency tree getting bigger.&lt;/li&gt;
&lt;li&gt;Complete example is available on &lt;a href="https://gitlab.com/ykyuen/glide-example"&gt;gitlab.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>glide</category>
    </item>
  </channel>
</rss>
