<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Things that make my head hurt</title>
    <description>Nic Jacksons coding and code related blog</description>
    <link>https://nicholasjackson.io/</link>
    <atom:link href="https://nicholasjackson.io/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sat, 13 Apr 2019 05:22:06 +0000</pubDate>
    <lastBuildDate>Sat, 13 Apr 2019 05:22:06 +0000</lastBuildDate>
    <generator>Jekyll v3.7.4</generator>
    
      <item>
        <title>Fixing Service Performance with PProf in Go</title>
        <description>&lt;p&gt;I tweeted the other day about how I managed to reduce the CPU consumption on one of my services by 90% by removing a single line of code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/tweet.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One of the things I did not do, mainly since it is difficult to make a full explanation in 256 characters is explain how I identified the problem and the process I took to locate the root cause.  This short post sets out to rectify that, and I hope it serves as a useful resource to save you all from repeating my embarrassing mistake.&lt;/p&gt;

&lt;h2 id=&quot;the-service&quot;&gt;The Service&lt;/h2&gt;
&lt;p&gt;The service I was working on was a simple API aggregation service; this exposes a public HTTP API consumed from a ReactJS website.  It interacts with two other upstream services, a cache which uses gRPC for the transport and a face detection service which is using Matt Ryer and David Hernandez &lt;a href=&quot;https://machinebox.io/docs/facebox&quot;&gt;FaceBox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I make no apologies for the implementation details of this service; it is not the model on an excellent microservice in fact there are components which really should be delegated out into other services. What I was building was a simple system which would allow me to demonstrate how to use the Consul Connect service mesh and Envoy’s reliability and observability features.  If you would like to take a look at the source code, you can find the link on GitHub: &lt;a href=&quot;https://github.com/emojify-app/api&quot;&gt;https://github.com/emojify-app/api&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-problem&quot;&gt;The Problem&lt;/h2&gt;
&lt;p&gt;The service itself was functioning fine, the latency was low, and there were no errors, but the CPU consumption did feel a little high for the traffic received and the work the service is doing.  Running this on my Kubernetes cluster it was easy to miss this, but when running this in an environment with lower resources it was a problem as the CPU consumption was starving the other services.  This unusual behavior caused me to start to take a look and investigate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Service CPU Consumption&lt;/strong&gt;
&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/before_cpu.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The above chart is showing the CPU consumption from the service; this might be nothing normal; looking at something like CPU without context is not the best way to draw a conclusion.  What started to look unusual was when I combined the CPU chart, an understanding on the actual work the service was doing at the time which was streaming files over a gRPC connection from another service, and the limited number of requests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Service Requests per Second&lt;/strong&gt;
&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/before_rps.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Something looks fishy here I have a hunch that there is something not quite right as I have built many Go based services and generally they are terrifically efficient on their CPU and memory consumption.  Let’s take a look at the upstream that the API is calling and see how that is performing as this service is responsible for sending the files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cache Service CPU&lt;/strong&gt;
&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/cache_cpu.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There is a dramatic difference there; the Cache is using 10% of the CPU of the API for the same number of requests.  This Cache service is reading from a file and sending the bytes of data as a gRPC message.  The API service receives that message and writes it as an HTTP response.  There is nothing complicated going on there; there should not be such a difference in the two services.&lt;/p&gt;

&lt;h2 id=&quot;investigating-the-problem&quot;&gt;Investigating the Problem&lt;/h2&gt;
&lt;p&gt;I was now pretty confident that there was a bug somewhere in the API service which was causing it to consume way too much CPU and I needed to investigate. Luckily for me Go has an excellent tool called pprof &lt;a href=&quot;https://golang.org/pkg/net/http/pprof/&quot;&gt;https://golang.org/pkg/net/http/pprof/&lt;/a&gt; which allows you to inspect the internal working of your application, you can see incredible detail like timings for memory allocation and the execution time for individual blocks of code.  Adding this to your code is also incredibly easy, so I decided, I would deploy a new build of my service with the diagnostics included so that I could run a profile.&lt;/p&gt;

&lt;p&gt;To enable profiling, I only had to add a couple of lines of code; the first was to import and enable the pprof package.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;net/http/pprof&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you already have a web server in your application, then pprof automatically attaches itself to &lt;code class=&quot;highlighter-rouge&quot;&gt;http.DefaultServeMux&lt;/code&gt; enables the API at the path &lt;code class=&quot;highlighter-rouge&quot;&gt;/debug/pprof/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I was not using the DefaultServeMux in my application as I am using the Gorilla Mux package for my http handlers.  Because I was using Gorilla, I had to add another line of code to enable the HTTP routing to pprof&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PathPrefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/debug/pprof/&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;DefaultServeMux&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After building and re-deploying my application with the instrumentation enabled I could then sample the running processes using the pprof tool.  Again this is a straightforward process; the pprof has excellent documentation on how to collect the different profiles, CPU, heap, blocking, etc.&lt;/p&gt;

&lt;p&gt;I point the pprof tool at my profile endpoint which is: &lt;code class=&quot;highlighter-rouge&quot;&gt;https://myservice/debug/pprof/profile?seconds=5&lt;/code&gt; this collects a five-second profile of the CPU.  The short profile is fine for my requirements as I know the requests are completing quickly, I don’t know why they are consuming so much CPU.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;go tool pprof &lt;span class=&quot;s2&quot;&gt;&quot;https://myservice/debug/pprof/profile?seconds=5&quot;&lt;/span&gt;
Fetching profile over HTTP from https://myservice/debug/pprof/profile?seconds&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5
Saved profile &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; /home/jacksonnic/pprof/pprof.emojify-api.samples.cpu.006.pb.gz
File: emojify-api
Type: cpu
Time: Mar 1, 2019 at 5:09am &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;UTC&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Duration: 5s, Total samples &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 40ms &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;  0.8%&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
Entering interactive mode &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;help&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;commands, &lt;span class=&quot;s2&quot;&gt;&quot;o&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;options&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;pprof&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Once I had the pprof tool running the first thing I like to do is to view a visual call trace of the collected profile, this allows me to zoom in quickly to the source of the problem. You need to have Graphviz installed to do this, but by merely executing the command pdf pprof outputs a graphical overview of the profile.&lt;/p&gt;

&lt;p&gt;The output looked like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/profile_before_1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Immediately I can see that &lt;code class=&quot;highlighter-rouge&quot;&gt;writeString&lt;/code&gt; in the protobuf package is consuming a considerable amount of the CPU.  Next step is to trace this back up to the source, in my code to understand why.&lt;/p&gt;

&lt;p&gt;Following the trace, I finally get to code I have written and saw this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/profile_before_2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The source of the problem seems to be a fmt.Println statement, time to dig into the code and see what that is doing and why it is even there.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;wrappers&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StringValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;err&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;So it seems that when I was debugging my application, I was writing the response from the gRPC cache service which is a protobuf message to StdOut.  Like a good developer, I forgot this was there and then deployed the application.  Serializing this protobuf message in this way was incredibly expensive, annoyingly it was also very unnecessary.&lt;/p&gt;

&lt;h2 id=&quot;fixing-the-service&quot;&gt;Fixing the Service&lt;/h2&gt;
&lt;p&gt;The fix could not be more straightforward, delete the line of code, rebuild and deploy the service again, with the new service deployed there was an immediate impact to the CPU consumption.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU post fix&lt;/strong&gt;
&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/after_cpu.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Over a 90% reduction in CPU, and what looks like far more normal operating conditions for the service with this traffic.  It is good to double check; however, so again I ran a profile, this time the profile showed the hot spot as syscall.  The result this time is what I would expect as the service is mainly reading and writing to a TCP socket.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CPU profile after fix&lt;/strong&gt;
&lt;img src=&quot;/images/posts/fixing-bugs-with-pprof/profile_after.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;I always say no experience is bad if you can learn something from it, I certainly learned that I am prone to making stupid mistakes, but it was also fun to dig into pprof again.  The whole process of finding the problem and fixing it took me approximately 30 minutes, this, of course, could have been so much longer had the issue not been so pronounced. However, it highlights just how amazing the tooling in the Go ecosystem is.&lt;/p&gt;

&lt;p&gt;If you want a takeaway, I have two:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Code review, a fresh pair of eyes would probably spot the unnecessary &lt;code class=&quot;highlighter-rouge&quot;&gt;Println&lt;/code&gt; statement&lt;/li&gt;
  &lt;li&gt;Profile your services before major deployments, it does not take long, and a quick eyeball of the results can save embarrassing mistakes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you would like to see more detail on the before and after traces, you can download a PDF from the following links:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Before: &lt;a href=&quot;/images/posts/fixing-bugs-with-pprof/profile001.pdf&quot;&gt;profile001.pdf&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;After: &lt;a href=&quot;/images/posts/fixing-bugs-with-pprof/profile002.pdf&quot;&gt;profile002.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One final thing, remember to remove the instrumentation from your service, especially if this is running in production.  I may or may not have just done this.&lt;/p&gt;

&lt;p&gt;Have fun,&lt;/p&gt;

&lt;p&gt;Nic&lt;/p&gt;
</description>
        <pubDate>Fri, 01 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2019/03/01/fixing-bugs-with-pprof/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2019/03/01/fixing-bugs-with-pprof/</guid>
        
        <category>go</category>
        
        
      </item>
    
      <item>
        <title>Travelling in China</title>
        <description>&lt;p&gt;China is a beautiful place to visit, rich in culture and charm.  For the western traveler, it may feel intimidating on your first visit as there are subtle differences to what you may be used to.  In this blog, I hope to set out some tips and tricks which will make your trip a success.&lt;br /&gt;
&lt;strong&gt;Disclaimer:&lt;/strong&gt; I am not a seasoned traveler in China only having had two fantastic trips to the county.  The items detailed below are not a comprehensive overview, but they have made my time in China far more enjoyable.&lt;/p&gt;

&lt;h2 id=&quot;visa&quot;&gt;Visa&lt;/h2&gt;
&lt;p&gt;The first and most important thing to note is that you are most likely going to need a Visa.  If you are planning on attending a conference such as KubeCon China, then you will need a business visa.  For tourism, a standard tourist visa will suffice.  The difference between the two is that a business visa requires a letter of invitation from the company or conference you are attending.  There is no one size fits all for this letter the details needed on it will depend from country to country.  Details of the invitation letter will be provided by your local embassy or visa agency.  Typically this includes items like full name, passport number, and expiry, home address, date of birth and gender.  The letter will also need to carry the official stamp from the authorized company and the signature and contact details of a company representative.&lt;/p&gt;

&lt;p&gt;It may be tempting to cut corners and just apply for a tourist visa instead of a business visa; personally, I have done this in the past with no problem.  However, if you are questioned at the point of entry you may be refused entry, my advice is, do not risk it and obtain the correct permit.  Visas also come in two different types, single entry and multi-entry, for the UK, both types allow you a stay not exceeding 90 days.  Often when applying for a single entry visa, you will be granted a multi-entry anyway.  Both types are valid for two years.  One thing to note is that you can only hold one Chinese visa at any time, if you already have a tourist visa and need to upgrade to a business visa then you will need to write a letter explaining why you wish to surrender and cancel your existing visa.  Business visas can be used for tourism but not the other way round.&lt;/p&gt;

&lt;p&gt;The visa application form is relatively straightforward however you will need to make a visit to your local embassy for an interview, you will also have to leave your passport with the embassy while they process your application.  Personally, I have always used an agency such as CIBIT in London who have managed this process for me, they will also ensure that the details on your form are correct before submitting it to the embassy.  Using an agency does carry an additional cost, but I think it is well worth it.&lt;/p&gt;

&lt;h2 id=&quot;airports&quot;&gt;Airports&lt;/h2&gt;
&lt;p&gt;Airports around the world are relatively homogenized, and it is no different in China, you will find the usual shops and coffee shops and long queues at immigration and security.  From an immigration stance upon arriving you will need to complete a landing card (remember to pack a pen).  This card comes in two parts one which is submitted on landing and one which you must present upon departure.  Keep your departure card safe as failure to provide this when you leave the country may cause problems when you next return to the country and could result in you being denied re-entry.&lt;/p&gt;

&lt;p&gt;Border patrol will check your passport and visa, you will be required to provide an electronic copy of your fingerprints, and your passport will be stamped.  Do not panic if you are taken to one side, often this is just a case of double checking with another border patrol member.  Concerning language, do not expect the border police to speak English, this is generally not a problem, and I have always found the process efficient and without issue.  All airports will have instructions and signage in both Chinese and English so navigating is never too much trouble.&lt;/p&gt;

&lt;h2 id=&quot;getting-around&quot;&gt;Getting around&lt;/h2&gt;
&lt;p&gt;Airports are generally situated 20+ KM from the center of the city very similar to how things are in the west.  There are sometimes public transport links to the center however after a 10+ hr flight the best option is often to take a taxi.  In general, the infrastructure for public transport is incredibly good, there has been a massive infrastructure investment in China over the last 10 years in this area, and it is incredibly good value.&lt;/p&gt;

&lt;h3 id=&quot;taxis&quot;&gt;Taxis&lt;/h3&gt;
&lt;p&gt;Taxis are cheap and plentiful, you will find a huge number of taxis at train stations and airports.  You will also find a large number of unsolicited drivers offering to take you to your destination.   In general no matter which country you visit, I find using an official taxi the safest option. Just follow the sign to the official taxi rank, there will be one in English and you will find it. Most likely you will also find a large queue of people waiting but the lines clear pretty fast.&lt;/p&gt;

&lt;p&gt;Taxis are not particularly expensive, a trip between Shanghai Hangdong airport and a hotel in the Bund, which is a trip of about 45 minutes (depending on traffic) will cost approximately 100 yuan (about 10 euro).  Do not expect the taxi drivers to speak English so ensure that you have the location of your hotel on your phone in Chinese which you can show the driver.  All licensed taxis run a meter, and this usually starts ticking up from about 14 yuan.&lt;/p&gt;

&lt;p&gt;Tipping does not seem to be the norm and can cause some confusion when you refuse your change.  Once the message does get through the gesture is always welcomed.&lt;/p&gt;

&lt;p&gt;Uber is not present in China, there is a local alternative Dede; however, I have not used this, my advice is if you do not have a written destination, then ask the hotel or restaurant to request a taxi for you and ensure they tell the driver where you wish to go to.  Most taxi drivers are honest and friendly people, especially when ordered from an official taxi rank or hotel.&lt;/p&gt;

&lt;p&gt;Should you hail a taxi from the street, do not be alarmed if you find a stranger in your cab.  Ride sharing is a thing in China, and some drivers may opportunistically attempt to double their fare by operating in this way.  This will not happen when you request a car from a hotel or take it from a train station.&lt;/p&gt;

&lt;p&gt;In general, taxis are in plentiful supply, and will generally only accept cash or mobile payment, I have not seen a taxi where it is possible to pay by credit card, so ensure you have enough currency on you to cover your trip.&lt;/p&gt;

&lt;h3 id=&quot;busses&quot;&gt;Busses&lt;/h3&gt;
&lt;p&gt;As previously mentioned the public transport infrastructure in China is incredibly good, and bus routes are everywhere.  Taking a bus is very cheap with a single trip costing about 2 yuan.  In the major cities, you will not be able to pay for the bus in cash, mobile payment is everywhere, and this seems to be the only way to pay for a bus.  Unless you are adventurous, my advice is to skip the bus and grab a cab.&lt;/p&gt;

&lt;h3 id=&quot;trains&quot;&gt;Trains&lt;/h3&gt;
&lt;p&gt;The trains in China are both efficient and cheap, they are also a great way to get between cities.  You can take the bullet train between Shanghai and Beijing in around 4 hours.  The train is comfortable, fast and a wonderful way to see the country which you would completely miss if flying.  Trains are also a fantastic way to travel shorter distances, a trip by train between Shanghai and Hangzhou, a distance of around 100 mile takes only 1hr and costs approximately 10 euro.  The simplest way to purchase tickets for trains is to use &lt;a href=&quot;https://trip.com&quot;&gt;Trip.com&lt;/a&gt; or even better the Trip.com app.  This app or website will show you the full train schedules and will allow you to purchase your tickets using a western credit card.&lt;/p&gt;

&lt;p&gt;Once you have purchased your tickets on trip.com, you will need to pick them up from the ticket office in the train station, the location of the ticket office usually is outside the central station before security.  Sometimes the ticket office will have an exclusive line for “Foreigners”, however do not expect the person at the booth to speak English.  Collecting your tickets is, however, a pretty simple process, Trip has a particular screen which you show to at the ticket office, you will also need your passport.  Hand both of these items over at the counter, and you will get back your ticket.  The ticket will have the number of the train, and time of departure printed at the top, it will also have your carriage and seat number printed in the top left.  To board the train, you will need to enter the central part of the station, and this is generally going to require that you show both your ticket and passport to security.  You will also have to put your luggage through the Xray machine similar to the experience at an Airport.  While this process is far quicker and nowhere near as thorough as Airport security the lines can be quite long at peak times.  Once through security you need to find your platform, the train departure boards in China are shown in both Chinese and in English.  Find your train number on the board and head to the gate (airport style) which is associated with that number.&lt;/p&gt;

&lt;p&gt;Train boarding generally starts about 10 minutes before departure and ends 5 minutes before departure so leave yourself plenty time to check in.  People will also begin to queuing early at the gate, and the gates will support multiple trains sometimes with only 10 minutes difference in departure.  You will be able to tell when it is time to board as your train number will show up green at the top of the board.  Again you will need to pass the barriers to get to the platform, this is a simple process, put your ticket in the gate, walk down to the platform and when the train arrives, get on board.  Trains in China are incredibly punctual, the seats are comfortable, they are fast and an excellent way to see the countryside as you hurtle along at 300KM/h.&lt;/p&gt;

&lt;h3 id=&quot;metro&quot;&gt;Metro&lt;/h3&gt;
&lt;p&gt;Chinese cities will generally have a metro system, the metro in the larger cities is very similar to what you may find in European cities with many different lines allowing you to get pretty much anywhere. Like European cities, the metro is crowded during peak times.  Tickets are cheap costing roughly 3 yuan (0.4 euro) for a single journey and tickets can be purchased from either the automated machines or from the ticket counters in the station.  In addition to single tickets, you can also buy day and week-long travel cards.  Disclaimer here, on my most recent trip I did not take the Metro, I mainly took a Taxi or walked to my destination.  I, however, plan to take the metro when I return to Shanghai in November and will update my blog then.&lt;/p&gt;

&lt;h3 id=&quot;walk&quot;&gt;Walk&lt;/h3&gt;
&lt;p&gt;Walking is always a great option when exploring, take advantage of the slower pace, look around (not at your phone), and enjoy.  Most cities can, however, be crowded to expect a reasonable amount of human traffic.  If you are used to a city like London, then there is nothing really to note, crossing the road is best done at the pedestrian crossings however in China, there is a considerable number of electric mopeds, expect these not to stop when you are crossing the road.  They do have to stop and will not deliberately run you over but just be careful before you step into the street.&lt;/p&gt;

&lt;p&gt;For navigation I found Google maps really reliable, that said, Google is mostly banned in China, but there are many ways around this, check out the “Connecting to the Internet” section of this post to ensure you can get access to maps.&lt;/p&gt;

&lt;h2 id=&quot;currency&quot;&gt;Currency&lt;/h2&gt;
&lt;p&gt;The currency in China is the Renminbi (RMB, peoples currency), you will find things generally referred to as “Yuan” which is also a basic unit of RMB.  This is similar to the UK where the currency is Sterling, but the units are Pounds and Pence. Notes and coins come in sizes from 1 yuan (1/10th of a euro) to 100 yuan (10 euros).&lt;/p&gt;

&lt;p&gt;There are cash machines everywhere where you can obtain money using your cash card and pin number, most of these will have an option for transacting in English, and they work exactly the same as you would expect anywhere in the world.  One thing to note is that every now and again you may find a cash machine which will not work with foreign cards, the best advice is to use Hotel cash machines or major Chinese banks.&lt;/p&gt;

&lt;p&gt;It is a good idea to always carry a small amount of cash with you, most places will readily accept credit cards however there is a movement towards mobile payment, and some stores (even large chains) will not accept credit/debit cards.  Taxis are generally happy with cash however again beware that they may be more used to receiving mobile payments and may not have change.  Another thing to note is since taxi drivers rarely speak English they may not be able to tell you they do not have change.  My advice here is to just round up your fair as a tip.  While tipping is not prevalent, it is always appreciated.&lt;/p&gt;

&lt;p&gt;Mobile payments are sweeping China by storm, most shops, big and small, taxis, railway stations, ok, everywhere accept them.  The two primary sources are WePay and AliPay.  WePay is built into the WeChat app (China’s whats app), it is a wallet style where you top up your WePay wallet with currency from a credit or debit card.  The rub for Foreigners is that while you may be able to add your card to WePay, do not expect it to allow you to top up.  There are two ways you can get around this, the first is to ask a local colleague or friend to send you a Red Letter, which is WeChat’s way of transferring currency between users.  The second is you can use a service such as &lt;a href=&quot;https://www.vpayfast.com/&quot;&gt;vpayfast.com&lt;/a&gt;, using this service you will be able to top up using your credit or debit card, and the service will send you a red letter for the amount through WeChat.  They will charge you 8% of the transaction as a fee, but this has been the only reliable way I have found to top up WeChat.  I think it is worthwhile to add 200 yuan to your WeChat wallet while in China, you never know when it will be useful, remember some small stores might not even accept cash.&lt;/p&gt;

&lt;p&gt;In my personal experience, I find my Monzo account works really well across the globe with favorable transfer rates and the convenience of being able to see what you are spending when you spend it.  Another option which I am planning on trying on my next trip is Transferwise,  with a Transferwise account you can hold local currency and spend this with the convenience of a master card debit card.&lt;/p&gt;

&lt;p&gt;Any major credit card Visa or Mastercard should be accepted except American Express which you may find you can only use in major hotels. Like traveling anywhere having a backup plan is always a good option.&lt;/p&gt;

&lt;h2 id=&quot;shopping&quot;&gt;Shopping&lt;/h2&gt;
&lt;p&gt;Like the rest of the world, walk down a shopping street in China and expect to find all of the usual brands.  Starbucks is everywhere, Zara, and all the other usual suspects, you will also find local brands.  To be honest, I have not really done a great deal of shopping so I can’t really comment on prices.&lt;/p&gt;

&lt;p&gt;The only thing I will note is to bring your attention back to something I mentioned in the currency section.  Do not be surprised if the store will only accept cash or mobile payments.  I experienced this when I went to buy a gift for my Nephew, the store was a busy modern chain called Line Friends.  The item in question a Teddy Bear, not especially cheap at 350 yuan.  I was surprised to find that when trying to pay that they would not accept my credit card and I was directed to mobile pay (which I could not use due to top up problems).  The cashier did not speak English (and why should we expect them to, it is not an English speaking country), and eventually figured out that they would accept cash.&lt;/p&gt;

&lt;p&gt;I can not confirm this 100%, but from speaking to my Chinese colleagues, it appears this is not unusual, as everything seems to be headed to the mobile pay route.  The key takeaway, do not expect to be able to use your credit card everywhere, cash is always a good bet, but you may find this is not accepted in some smaller stores.  Mobile payment is king.&lt;/p&gt;

&lt;h2 id=&quot;food&quot;&gt;Food&lt;/h2&gt;
&lt;p&gt;Food in China is delicious, I may be biased as it is one of my favorite international cuisines but my recommendation is to embrace this and take every opportunity you can do dine like a local.  The menus are probably not what you will see in Chinese restaurants in the West as these have been primarily homogenized, but the dishes are not so different.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/travelling-china/hairy_crab.jpg&quot; alt=&quot;Hairy leg crab&quot; /&gt;
&lt;em&gt;Hairy leg crab&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hairy leg crab is a delicacy, found in the late summer, the crabs spend their life in the paddy fields where their presence helps the rice grow.  Then unfortunately for the crab and enjoyment of diners, it is time for the dinner table.  &lt;strong&gt;Disclaimer:&lt;/strong&gt; while I embraced local food and rarely eat anything else when in China, I have a general rule where I will not eat anything with a face.&lt;/p&gt;

&lt;p&gt;In addition to local foods, you will also be able to find the usual suspects, Starbucks is everywhere, Macdonalds on most corners but do your best to avoid these and embrace the local culture.  A meal for two people in a modest restaurant will cost you less than 200 yuan which is excellent value.  Compare this to a double espresso in Starbucks (roughly 20 yuan) or a double shot skinny latte (35 yuan), and it seems excellent value.  My main benchmark for the price of food in a country is often the Big Mac meal, in China, this is roughly 35 yuan or 3.5 euros.&lt;/p&gt;

&lt;p&gt;You will find that menus are often only written in Chinese but will have pictures, there will usually be English translations or photographs for food in the larger cities.  Again do not expect the restaurant staff to either speak English and you may have trouble trying to pay with your western credit card. Cash is generally the best option and always a good backup.&lt;/p&gt;

&lt;p&gt;The menu will differ depending upon the region you are in, and it is going to be rare to find vegetarian food as almost everyone is an omnivore.&lt;/p&gt;

&lt;p&gt;Vegetarians beware, while you will find many vegetable dishes on the menu, often these are prepared with either meat or fish stock.  Large hotels might be your best bet if you do not eat meat or fish, they will be best to cater to your needs.&lt;/p&gt;

&lt;h2 id=&quot;language&quot;&gt;Language&lt;/h2&gt;
&lt;p&gt;For the traveler who is used to Europe do not expect Chinese people to speak English as a second language.  Hotels will almost always have staff able to speak English but shops, taxi drivers, restaurants, and even Starbucks will most likely not.&lt;/p&gt;

&lt;p&gt;Also, remember that the Chinese alphabet (Pinyin) is not going to be easily readable as each symbol is a sound rather than individual letters forming works.  Many larger establishments, train stations, airports, and road signs will be written in both Chinese and English which makes navigation easy enough, but it is not prevalent.&lt;/p&gt;

&lt;p&gt;A tip for taxis is always to have your destination written in Chinese which you can show to the driver on your mobile phone.  Google translate is also a potential option.  The best bet when getting a taxi from a hotel is to ask the concierge to request a cab for you and to ensure that the driver knows the destination.&lt;/p&gt;

&lt;p&gt;Learning Chinese for a short trip is probably not going to be an option for you, however, no matter where I travel I find it is respectful to at least be able to say Hello, Goodbye, Please and Thank You in the local language:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Hello - Ni Jiao&lt;/li&gt;
  &lt;li&gt;Goodbye - Zai Jian&lt;/li&gt;
  &lt;li&gt;Thank You - XieXie (c c)&lt;/li&gt;
  &lt;li&gt;Please - Qing (ching)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many excellent options for learning the language Duolingo has a great free course which I highly recommend.&lt;/p&gt;

&lt;h2 id=&quot;safety&quot;&gt;Safety&lt;/h2&gt;
&lt;p&gt;I am unable to comment on what the level of crime is like in China, what I can say is that on my two trips I have never felt unsafe. There is a high presence of Police in most cities and train stations and pickpocketing, or petty crime does not seem to be a problem.  That said, apply the rules you would in any city, keep your purse or wallet secure on your person and do not leave your belongings lying around.&lt;/p&gt;

&lt;p&gt;There are generally plenty of people about even late in the evening, and my personal recommendation is to take the same level of care you would if you are traveling to London.  I felt completely at ease walking around China, and as a 2m tall white guy I certainly stand out in the crowd.  Occasionally you will be approached by beggars, but this is really rare even in a city as big as Shanghai.  They are never threatening and will leave you alone eventually, but if you do have a little change, it will be very well appreciated.&lt;/p&gt;

&lt;p&gt;Like any unfamiliar country it takes time to adapt to your surroundings, but after a couple of days, you will be navigating like a native.  Do not worry, be sensible and you will have a fantastic time.&lt;/p&gt;

&lt;h2 id=&quot;connecting-to-the-internet&quot;&gt;Connecting to the Internet&lt;/h2&gt;
&lt;p&gt;Ok techies, this is probably the thing most important to you, connecting to the internet either on your phone or computer is going to be essential to a good trip.  The great firewall will stop you from accessing things like Google search, Google maps, and Gmail; however, this can typically be circumvented by using a VPN.  In the rest of the world I am a big fan of Tunnel Bear; however, I found this somewhat patchy in China.  I recommend you try &lt;a href=&quot;https://www.expressrefer.com/en/refer-a-friend/30-days-free?utm_campaign=refer_friends&amp;amp;utm_medium=copy_link&amp;amp;utm_content=iosmenu_get30daysfree&amp;amp;utm_source=ios_app&amp;amp;referrer_id=21726901&quot;&gt;ExpressVPN&lt;/a&gt;, this will work on your laptop, iDevice and Android platforms.  My recommendation is you to set this up before you leave as some of the download sites can be blocked once in the country.&lt;/p&gt;

&lt;p&gt;China has first-class mobile broadband, if you think people in the West are obsessed with their phones, China takes this to a new level.  I am on Vodafone in the UK and using my plan in China costs an additional 6 euros per day which is well worthwhile.  Interestingly I found that Google services would mostly work from my iPhone while I was roaming on the 4G network.  I am not sure if this is because the system knows I am a foreigner.  In general however even when on a mobile network I find that running ExpressVPN is your best chance to ensuring a reliable connection to all my Google services.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;China is a beautiful country and the Chinese are wonderfully warm and welcoming.  The food is fantastic, the infrastructure makes it so easy to travel around, and the scenery breathtaking.&lt;/p&gt;

&lt;p&gt;Don’t be put off by comments like China is so polluted,  China is so busy you cannot move,  in my experience,, this is over exaggerated, I live in London where we have some of the worst air quality in the world, and as for congested, we take things to the next level.  China is making amazing inroads to improve the quality of life in the cities.  You will not find more electric vehicles anywhere on the planet,  the train network is world class, yes there are traffic jams, but there are traffic jams in any large city.&lt;/p&gt;

&lt;p&gt;As for the pace of life, is China, frantic, fast moving, exhausting?  The pace of life moves at a speed you want it to, you can have a wonderfully relaxing time, just run at your own pace.  Embrace the culture, drink tea, not coffee, eat noodles not a burger, enjoy the juxtaposition between rich history and modern metropolis.  I hope this article helps and the pleasant memories from your trip last a lifetime.&lt;/p&gt;
</description>
        <pubDate>Sun, 14 Oct 2018 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2018/10/14/travelling-in-china/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2018/10/14/travelling-in-china/</guid>
        
        <category>other</category>
        
        
      </item>
    
      <item>
        <title>Controlling your Holiday Lights with Raspberry Pi, Alexa and Go</title>
        <description>&lt;p&gt;In this post, we are going to take a look at how we can control the lights on your tree using the Amazon Alexa and a Raspberry Pi.&lt;/p&gt;

&lt;p&gt;Why?&lt;/p&gt;

&lt;p&gt;Two reasons, firstly because we can, and secondly there is an unusual architectural pattern which needs to be addressed when attempting to bridge the gap between your home and the internet.  How does the IOT device running in a NAT’etd environment receive messages from the outside world.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt;  The code is not necessarily production worthy, it might work through Xmas, there are more clicking on interfaces than I would generally like.&lt;/p&gt;

&lt;h2 id=&quot;requirements&quot;&gt;Requirements&lt;/h2&gt;
&lt;p&gt;To create this system, you will need the following components:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;1 Raspberry Pi (Any model with network will do)&lt;/li&gt;
  &lt;li&gt;1 433MHz TX/RX module for the Pi - &lt;a href=&quot;https://www.amazon.co.uk/Aukru-Wireless-Transmitter-Receiver-Raspberry/dp/B00OLI93IC/ref=sr_1_3?ie=UTF8&amp;amp;qid=1514130535&amp;amp;sr=8-3&amp;amp;keywords=433mhz+transmitter&quot;&gt;Aukru 433 MHz RF Wireless Transmitter + Receiver Module: Amazon.co.uk: Electronics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;1 Amazon Echo&lt;/li&gt;
  &lt;li&gt;Cheap 433MHz radio controlled power sockets- &lt;a href=&quot;https://www.amazon.co.uk/Control-Wireless-Adaptor-Controlled-Operation-White/dp/B0068JOTTA/ref=sr_1_3?s=electronics&amp;amp;ie=UTF8&amp;amp;qid=1514130574&amp;amp;sr=1-3&amp;amp;keywords=radio+control+power+sockets&quot;&gt;Remote Control Socket Wireless Heavy Duty 13A Adaptor: Amazon.co.uk: Electronics&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;AWS account&lt;/li&gt;
  &lt;li&gt;Internet&lt;/li&gt;
  &lt;li&gt;Some programming knowledge&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;architecture&quot;&gt;Architecture&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/overview.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;When you issue a command to Alexa “Hey Alexa, ask Christmas tree lights to turn on,”&lt;/li&gt;
  &lt;li&gt;The language processing in  AWS will transform this command into a call to a Lambda function.&lt;/li&gt;
  &lt;li&gt;The Lambda function adds a message to a Simple Queue Service message queue&lt;/li&gt;
  &lt;li&gt;The app running on the Pi is reads this message queue&lt;/li&gt;
  &lt;li&gt;It then transmits a code corresponding to on/off over 433MHz radio which is then picked up by your radio controlled power plug&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using SQS allows us to bypass the fact the Pi needs to be exposed to the internet.  The Pi makes an outbound connection to the SQS and sits waiting for messages.&lt;/p&gt;

&lt;h2 id=&quot;configuring-the-raspberry-pi&quot;&gt;Configuring the Raspberry Pi&lt;/h2&gt;
&lt;p&gt;The first thing to get started is to configure the Pi and the 433Mhz transmitter.  Before we can switch our lights on and off, we need to determine what codes are used by your power sockets.  To do this, we are going to attach the receiver portion of the 433MHz radio to the Pi we can then sniff for codes by pressing the buttons on your remote.&lt;/p&gt;

&lt;p&gt;The way that the power sockets work is that a binary code is transmitted over the radio.  The protocol uses a sequence of radio waves to signify the 1s and 0s in the code.  The protocol defines what duration between the highs and the lows and that corresponds to a 1 or a 0 in the code.&lt;/p&gt;

&lt;p&gt;Grab your Raspberry Pi and attach the Transmitter to the GPIO pins, you will need to connect the VCC pin on the transmitter to the 5v power pin on the Pi, I am using pin 2 and the GND to the ground pin on the Pi, I am using pin 3.  Lastly you connect the DATA pin to one of the GPIO pins, I am using pin 4.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/wiring.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;You then need to run the application on your Pi and set it to scan mode; you can find a compiled version of the application in the GitHub repository:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/nicholasjackson/rcswitch/releases&quot;&gt;Releases · nicholasjackson/rcswitch · GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will need to choose the appropriate version for your PI Arm6 is used for Pi Zeros and first-generation Pi’s and the Arm7 version is suitable for the Pi model 3.&lt;/p&gt;

&lt;h3 id=&quot;deep-in-the-code&quot;&gt;Deep in the code&lt;/h3&gt;
&lt;p&gt;The code is written in Golang and uses the &lt;a href=&quot;https://periph.io&quot;&gt;Periph.io&lt;/a&gt; library to interface to the GPIO pins.  The first thing we need to do is to initialize the &lt;a href=&quot;https://periph.io&quot;&gt;Periph.io&lt;/a&gt; library using the Init function.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;examples/main.go&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Init&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can then get a reference to our pin and start scanning for codes:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Lookup a pin by its number:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpioreg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setPin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s: %s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcswitch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// scan for codes&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Starting code detection, press a button on your remote control&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We set the pin mode based on whether we want to send or receive codes for receiving we set the pin to input mode with edge detection for transmitting we set the pin to output mode.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;// sets the pin to either input or output depending on if we are scanning&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setPin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PinIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Set it as input, with an internal pull down resistor:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;In&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PullDown&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BothEdges&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;High&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Internally the &lt;code class=&quot;highlighter-rouge&quot;&gt;Scan&lt;/code&gt; function uses the &lt;code class=&quot;highlighter-rouge&quot;&gt;WaitForEdge&lt;/code&gt; feature of the pin, whenever the pin changes state, i.e., low to high.  We record the durations between these changes and this allows us to parse against the known protocols and transform it to a string representing the switch message.&lt;/p&gt;

&lt;p&gt;My Go library which works with Periph.io can be found here:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/nicholasjackson/rcswitch&quot;&gt;https://github.com/nicholasjackson/rcswitch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This library has been ported from a C++ library written by &lt;a href=&quot;https://github.com/sui77&quot;&gt;Suat Özgür&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/sui77/rc-switch&quot;&gt;https://github.com/sui77/rc-switch&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&quot;detecting-codes&quot;&gt;Detecting codes&lt;/h3&gt;
&lt;p&gt;Run the example application on your Pi setting the correct pin and scan mode, and we can press some buttons on our remote and capture the codes.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;pi@pi04:~ &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;./rcswitch_arm6 &lt;span class=&quot;nt&quot;&gt;-pin&lt;/span&gt; 4 &lt;span class=&quot;nt&quot;&gt;-scan&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;true
&lt;/span&gt;2017/12/24 13:14:20 GPIO4: In/Low
2017/12/24 13:14:20 Starting code detection, press a button on your remote control
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now press the &lt;code class=&quot;highlighter-rouge&quot;&gt;off&lt;/code&gt; button on your remote which corresponds to the power plug you would like to control, hopefully, if your sockets are supported by the library you should see the application output something like the following.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2017/12/24 13:14:23 decimal: 16404 // off
2017/12/24 13:14:23 binary: 000000000100000000010100
2017/12/24 13:14:23 bitlength: 24
2017/12/24 13:14:23 protocol: 0
2017/12/24 13:14:23 
2017/12/24 13:14:25 decimal: 16405 // on
2017/12/24 13:14:25 binary: 000000000100000000010101
2017/12/24 13:14:25 bitlength: 24
2017/12/24 13:14:25 protocol: 0
2017/12/24 13:14:25 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will need to record the code and the protocol that is output so copy this down for use later on.  We can now do the same for the &lt;code class=&quot;highlighter-rouge&quot;&gt;on&lt;/code&gt; button, again record this code; the protocol should be the same.&lt;/p&gt;

&lt;h2 id=&quot;setting-up-sqs&quot;&gt;Setting up SQS&lt;/h2&gt;
&lt;p&gt;Now we have the codes we can go ahead and create an SQS queue for the application in AWS.  Go to the AWS console and click on the SQS section.&lt;/p&gt;

&lt;p&gt;Click create new queue and fill in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Queue Name&lt;/code&gt;
Choose &lt;code class=&quot;highlighter-rouge&quot;&gt;Standard Queue&lt;/code&gt;
Click configure queue and change the message retention period to &lt;code class=&quot;highlighter-rouge&quot;&gt;1 minute.&lt;/code&gt;
Click create queue
Click Permissions and add two actions&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;SQS:ReceiveMessage&lt;/li&gt;
  &lt;li&gt;SQS:SendMessage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/sqs.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Copy the address for the SQS queue from the details tab; we are going to need this for the application which will listen to messages on the queue.&lt;/p&gt;

&lt;h2 id=&quot;running-the-receiver-application-on-the-pi&quot;&gt;Running the receiver application on the Pi&lt;/h2&gt;
&lt;p&gt;We can now run our application on the Pi which will receive these codes and use the &lt;code class=&quot;highlighter-rouge&quot;&gt;rcswitch&lt;/code&gt; library to transmit the codes.&lt;/p&gt;

&lt;p&gt;You can find the source code for the application, including compiled binaries if you do not wish to build it yourself:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/nicholasjackson/xmas-lights-v2&quot;&gt;https://github.com/nicholasjackson/xmas-lights-v2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disconnect the receiver from your Pi and connect the transmitter, again the VCC connects to the power on pin 2, GND to pin 3, and the DATA to pin 4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;main.go&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;x&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Setup the GPIO settings for the 433MHz transmitter&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpioreg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ByName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fatal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Unable to find pin: &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpio&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;High&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s: %s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rcswitch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;onCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OffCode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Protocol&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SqsURI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqsURI&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Create a new SQS Vice transport&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sqs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// Create a new instances of the lights application and setup the transport&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lights&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;New&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Println&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Listening for messages&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We again grab a reference to our GPIO pin using the Periph.io library and configure the package with our codes which we captured earlier, the protocol, and the address for the SQS queue.&lt;/p&gt;

&lt;p&gt;Internally we are using the excellent &lt;code class=&quot;highlighter-rouge&quot;&gt;Vice&lt;/code&gt; library created by Mat Ryer:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/matryer/vice&quot;&gt;https://github.com/matryer/vice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vice provides a common abstraction for many different queues such as SQS, and NATS.io streaming and provides us with a Go channel which we can listen to for messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;lights/lights.go&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Lights&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Listen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;range&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;messageChan&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;decodeMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandTurnOn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swtch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OnCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CommandTurnOff&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;swtch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;OffCode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Protocol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For Vice to be able to connect to SQS you will need to set some environment variables corresponding to your AWS account.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;AWS_SECRET_ID&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;xxxxxxx
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;AWS_SECRET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;xxxxxxx
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;AWS_REGION&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=[&lt;/span&gt;YOUR AWS REGION] // i.e. eu_west_1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now run the application using all the information provided earlier and go ahead and create our Alexa skill.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;./lights &lt;span class=&quot;nt&quot;&gt;-pin&lt;/span&gt; 4 &lt;span class=&quot;nt&quot;&gt;-on_code&lt;/span&gt; 0000001101010 &lt;span class=&quot;nt&quot;&gt;-off_code&lt;/span&gt; 00000110100 &lt;span class=&quot;nt&quot;&gt;-protocol&lt;/span&gt; 0 &lt;span class=&quot;nt&quot;&gt;-sqs_uri&lt;/span&gt; http://something.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;setting-up-the-alexa-skill&quot;&gt;Setting up the Alexa skill&lt;/h2&gt;
&lt;p&gt;Open the Alexa development console and click the &lt;code class=&quot;highlighter-rouge&quot;&gt;Get Started&lt;/code&gt; button below Alexa Skills Kit &lt;a href=&quot;https://developer.amazon.com/edw/home.html#/&quot;&gt;https://developer.amazon.com/edw/home.html#/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code class=&quot;highlighter-rouge&quot;&gt;Add New Skill&lt;/code&gt;.
Give your skill a name and an invocation name.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code class=&quot;highlighter-rouge&quot;&gt;Save&lt;/code&gt;, then press &lt;code class=&quot;highlighter-rouge&quot;&gt;Next&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We now need to configure the details for our Skill; this includes the things that the skill will respond to &lt;em&gt;(Intents)&lt;/em&gt; and variables which will be extracted from the command and sent to the Lambda function &lt;em&gt;(Slots)&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First, click the menu on the left and add a new &lt;code class=&quot;highlighter-rouge&quot;&gt;Slot Type&lt;/code&gt;.
Give it a name of  &lt;code class=&quot;highlighter-rouge&quot;&gt;onoff&lt;/code&gt;
Next step is to configure the values for the slot, and unsurprisingly these will be &lt;code class=&quot;highlighter-rouge&quot;&gt;on&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;off&lt;/code&gt;, add these values using the UI.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now add an intent by clicking the &lt;code class=&quot;highlighter-rouge&quot;&gt;ADD&lt;/code&gt; button on the left-hand menu, give the Intent a name of &lt;code class=&quot;highlighter-rouge&quot;&gt;SwitchLights&lt;/code&gt;.  If you change the name of the Intent or the Slots, you will need to change the Lambda and the application code.&lt;/p&gt;

&lt;p&gt;We are going to add two sample utterances:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;“turn {onoff}”&lt;/li&gt;
  &lt;li&gt;“switch {onoff}”&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The curly brackets tell the skill that we would like to detect values defined in our &lt;code class=&quot;highlighter-rouge&quot;&gt;onoff&lt;/code&gt; slot created in the previous step.  When you issue a command to Alexa these values will be extracted and sent with the request to the Lambda function.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Before saving make sure that you select the &lt;code class=&quot;highlighter-rouge&quot;&gt;Slot Type&lt;/code&gt; by clicking on the slot on the right-hand side and then selecting the Slot Type from the new dialog box.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Your intent should now look like the following example:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa6.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now we can &lt;code class=&quot;highlighter-rouge&quot;&gt;Save&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;Build&lt;/code&gt; our model.&lt;/p&gt;

&lt;h2 id=&quot;creating-our-lambda&quot;&gt;Creating our Lambda&lt;/h2&gt;
&lt;p&gt;The next step is to create a Lambda function which will be called by the Alexa skills kit.  This function is going to be written in Node.js.&lt;/p&gt;

&lt;p&gt;Go to the AWS Lambda section of the AWS consul and select create new lambda, we are going to create a lambda using one of the blueprints as we will need the Alexa SDK node module.  Click create lambda from blueprint and choose &lt;code class=&quot;highlighter-rouge&quot;&gt;alexa-skill-kit-sdk-factskill&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/lambda1.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;code class=&quot;highlighter-rouge&quot;&gt;Configure&lt;/code&gt; and on the next screen give your function a name.
Next we need to create a &lt;code class=&quot;highlighter-rouge&quot;&gt;Role&lt;/code&gt; for the function which has permissions to write to logs and also write messages to the SQS queue.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/lambda2.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Choose &lt;code class=&quot;highlighter-rouge&quot;&gt;Create a custom role,&lt;/code&gt; and the dialog will change to allow you to configure the role.&lt;/p&gt;

&lt;p&gt;The default options will be fine however we do need to add the queue permissions, click the edit button and when asked if you have read the documentation nonchalantly click “OK” because nobody reads the documentation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/lambda3.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We need to modify the policy; you should be able to replace the contents of the box with the details listed below.  You will need to replace &lt;code class=&quot;highlighter-rouge&quot;&gt;[YOUR ARN HERE]&lt;/code&gt; with the ARN of the queue that you created earlier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IAM Policy&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2012-10-17&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Statement&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;logs:CreateLogGroup&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;logs:CreateLogStream&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;logs:PutLogEvents&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;arn:aws:logs:*:*:*&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Action&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
                &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sqs:SendMessage&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Effect&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Allow&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Resource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;[YOUR ARN HERE]&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When you return to the Lambda console, make sure the role you have just created is selected in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Existing role&lt;/code&gt; drop down box and click create function.&lt;/p&gt;

&lt;p&gt;Now go down to the code editor and delete all of the code which is in there.&lt;/p&gt;

&lt;p&gt;We are going to replace all of the code with our function which is listed below:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;handler.js&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Alexa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'alexa-sdk'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;QUEUE_URL&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'https://sqs.eu-west-1.amazonaws.com/xxxxxxxx/xmaslights'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'aws-sdk'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sqs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;AWS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SQS&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;region&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'eu-west-1'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;handlers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'SwitchLights'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;//this.emit(':tell','Ok, Merry Christmas')&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onoff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;on&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;off&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':tell:'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Sorry I can only turn the lights on and off'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;MessageBody&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}),&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;QueueUrl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;QUEUE_URL&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;sqs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sendMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':tell'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Sorry, something went wrong, maybe you are not a dope coder after all'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':tell'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Ok, Merry Christmas'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
    
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
  &lt;span class=&quot;s1&quot;&gt;'Unhandled'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;':ask'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Sorry, I dont know how to do that'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  
&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alexa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Alexa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;alexa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;appId&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;amzn1.ask.skill.xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx&quot;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;alexa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;registerHandlers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handlers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;alexa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will need to replace the placeholder &lt;code class=&quot;highlighter-rouge&quot;&gt;QUEUE_URL&lt;/code&gt; with the address of your SQS queue that you created earlier.  You also need to change &lt;code class=&quot;highlighter-rouge&quot;&gt;alexa.appId&lt;/code&gt; value and set that to your app id.  You can find the app id in the grey bar at the top of the developer console.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;Save&lt;/code&gt; your function.&lt;/p&gt;

&lt;p&gt;We can now go ahead and test our function, all of the parts should be in place to send a test request which will send a message which will be picked up by our Raspberry Pi.&lt;/p&gt;

&lt;p&gt;Click test and configure a new test message which corresponds to the listing below:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;session&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;new&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sessionId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SessionId.04916bd6-7f39-49fb-8860-d8b0ae4b7465&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;applicationId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;amzn1.ask.skill.fb690610-84f3-4e8f-b38c-d13f727195a9&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;attributes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;amzn1.ask.account.AFQHEN5Q3F5JEM6ZB2SGUQ6IQTRVKV75SNENKTWYRBA2OD4QL427QLHEEST7GI2GQ42WDLJUEAYTNXXXXX4K27YZCAMYTJCIQGZV2ZRIHFWZ7BMRTI7XXXXXXFN2F7LKCM2ED6NZDGL6MYVWOQJVTUEMYIRHKHVGFXKOV3XVMILXZVN2WJARPLKCQPFXQ6QGQ57RIHY&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;IntentRequest&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;requestId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;EdwRequestId.cfdaab4a-af02-4d76-be6a-e235c4323072&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;intent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SwitchLights&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;slots&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;onoff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;onoff&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;value&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;on&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;locale&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;en-GB&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;timestamp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2017-12-23T16:18:21Z&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;context&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;AudioPlayer&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;playerActivity&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;IDLE&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;System&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;application&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;applicationId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;amzn1.ask.skill.fb690610-84f3-4e8f-b38c-d13f727195a9&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;user&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;amzn1.ask.account.AFQHEN5Q3F5JEM6ZB2SXXXXXXRVKV75SNENKTWYRBA2OD4QL427QLHEESTXXXXXX2WDLJUEAYTN7W5VGTXPSZ4K27YZCAMYTJCIQGZV2ZRIHFWZ7BMRTI7DGUA5P5N7FN2F7LKCXXXXXGL6MYVWOQJVTUEMYIRHKHVGFXKOV3XVMILXXXXRPLKCQPFXQ6QGQ57RIHY&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;device&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;supportedInterfaces&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All being well when you press test, your switch should have turned on, if you look at the output in the log from the application running on the Raspberry Pi you should see that it has received a message and has transmitted our code.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/lambda4.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2017/12/24 15:09:26 Starting lights: v0.1
2017/12/24 15:09:26 GPIO4: Out/High
2017/12/24 15:09:26 Listening &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;messages
2017/12/24 15:10:12 Received Message: &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;123 34 99 111 109 109 97 110 100 34 58 34 111 110 34 125]
2017/12/24 15:10:12 Sending turn on with code: 000000000100000000010101
2017/12/24 15:10:12 Transmitting: 000000000100000000010101
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Select &lt;code class=&quot;highlighter-rouge&quot;&gt;Publish a new Version&lt;/code&gt; from the &lt;code class=&quot;highlighter-rouge&quot;&gt;Actions&lt;/code&gt; menu; then we need to add a trigger.&lt;/p&gt;

&lt;p&gt;Back at the top in the designer section, we need to add a trigger for Alexa, select the &lt;code class=&quot;highlighter-rouge&quot;&gt;Alexa Skills&lt;/code&gt; trigger from the menu on the left and then configure the options which allows Alexa to call your function.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/lambda5.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Finally, copy the ARN for the lambda which will look something like this: &lt;code class=&quot;highlighter-rouge&quot;&gt;arn:aws:lambda:eu-west-1:38390000802431:function:xmaslights2:11&lt;/code&gt; and go back to the Alexa skills developer portal.&lt;/p&gt;

&lt;h2 id=&quot;configuring-alexa-with-lambda&quot;&gt;Configuring Alexa with Lambda&lt;/h2&gt;
&lt;p&gt;If you click on the configuration menu option, you can paste your Lambda’s ARN into the box.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa7.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Click the next button, and we should be able to test our setup.  In the test box type an example command like the following:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Ask Christmas lights to switch on.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see a successful response in the output window, and the remote switch should enable.  To switch the lights off, we can use a corresponding command”:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Ask Christmas lights to switch off.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa8.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Assuming all of this is now working the last step is to check the box which enables testing of your function, and we can add the skill to our account and try it with our Echo.&lt;br /&gt;
If this box is not available, make sure you have linked your Echo device with your Developer account. &lt;a href=&quot;https://developer.amazon.com/docs/custom-skills/test-a-custom-skill.html#h2_register&quot;&gt;https://developer.amazon.com/docs/custom-skills/test-a-custom-skill.html#h2_register&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/xmas-lights/alexa9.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;all-together-now&quot;&gt;All together now&lt;/h2&gt;
&lt;p&gt;The last thing we need to do is to give it a test; you should now be able to say to Alexa.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Alexa, ask Christmas lights to switch on.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;video width=&quot;730&quot; height=&quot;514&quot; controls=&quot;&quot;&gt;
  &lt;source src=&quot;/images/posts/xmas-lights/xmas-lights.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;And the result, instance festive cheer.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;This walkthrough has shown you how you can create a simple Alexa skill and how you can link this to an IOT device such as the Raspberry Pi.   Now when dragging your self off to bed after far too much Christmas turkey, you no longer need to find the remote buried under piles of wrapping paper just command your faithful robot:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&quot;Alexa, ask Christmas lights to turn off.&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Happy holidays&lt;/p&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Source Code&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/nicholasjackson/xmas-lights-v2&quot;&gt;https://github.com/nicholasjackson/xmas-lights-v2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RCSwitch Go Libary for Periph.io&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/nicholasjackson/rcswitch&quot;&gt;https://github.com/nicholasjackson/rcswitch&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;433MHz Switch Protocol Info&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/sui77/rc-switch/wiki/KnowHow_LineCoding&quot;&gt;https://github.com/sui77/rc-switch/wiki/KnowHow_LineCoding&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 24 Dec 2017 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2017/12/24/alexa-xmas-lights/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2017/12/24/alexa-xmas-lights/</guid>
        
        <category>bots</category>
        
        <category>serverless</category>
        
        <category>node</category>
        
        <category>lex</category>
        
        <category>raspberrypi</category>
        
        <category>go</category>
        
        
      </item>
    
      <item>
        <title>Building a Slackbot with AWS Lambda and Lex</title>
        <description>&lt;p&gt;This post is intended to walk you through creating a Slackbot with AWS Lambda and Lex.  I am not using any of the Lambda frameworks like &lt;a href=&quot;http://serverless.com&quot;&gt;Serverless&lt;/a&gt; or &lt;a href=&quot;http://apex.run&quot;&gt;Apex&lt;/a&gt; in this post instead demonstrates how it is possible to create a Lambda function with pure Node and deploy using HashiCorps &lt;a href=&quot;http://terraform.io&quot;&gt;Terraform&lt;/a&gt;.
The simple application is a bot which listens for messages that correspond to the phrase “Which timezone is [user] in?” it then calls the Slack API and retrieve the timezone for that particular user.  Lex has the capability of defining an &lt;em&gt;Intent&lt;/em&gt; which is a request; the natural language processing means that we do not need to cater for every permutation of the question such as:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Which timezone is nic in?&lt;/li&gt;
  &lt;li&gt;What timezone is nic in?&lt;/li&gt;
  &lt;li&gt;Hey @otheruser what timezone is nic in?
The Lex runtime selects the best intent based on its natural language processing.  In addition to this, we can define variables or &lt;em&gt;Slots&lt;/em&gt; which Lex extracts out of the intent and pass to the function.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the source code for this post at &lt;a href=&quot;https://github.com/nicholasjackson/slack-bot-lex-lambda&quot;&gt;https://github.com/nicholasjackson/slack-bot-lex-lambda&lt;/a&gt;:&lt;/p&gt;

&lt;h2 id=&quot;step-1-creating-the-lambda-function&quot;&gt;Step 1: Creating the Lambda function&lt;/h2&gt;
&lt;p&gt;To add interactivity to Lex we can pass an intent to a Lambda function, in our example, this function is going to call the slack API and fetch the Timezone that matches the given user.&lt;/p&gt;

&lt;h3 id=&quot;filesrcindexjs&quot;&gt;file://src/index.js&lt;/h3&gt;
&lt;p&gt;If we take a look at &lt;em&gt;src/index.js&lt;/em&gt; in the code repository, we see that it is a relatively simple Javascript lambda handler.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*jslint node: true */&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;02&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*jslint esversion: 6 */&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'use strict'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;05&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;PATH&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;':'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;LAMBDA_TASK_ROOT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;06&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;07&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'slack'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;08&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;dispatcher&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dispatcher'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;09&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// --------------- Main handler -----------------------&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loggingCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;originalCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;    &lt;span class=&quot;nx&quot;&gt;originalCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// Route the incoming request based on intent.&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// The JSON body of the request is provided in the event slot.&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;handler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// By default, treat the user request as coming from the America/New_York time zone.&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;TZ&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'America/New_York'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`event.bot.name=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bot&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;loggingCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first thing to note is &lt;em&gt;line 5&lt;/em&gt; because we are going to be bundling a couple of node modules with our Lambda function we need to configure the environment path to be able to pick these up.  The path only needs to be set once and not on every file.
We are also importing a couple of local modules &lt;em&gt;slack&lt;/em&gt; which is our slack client and &lt;em&gt;dispatcher&lt;/em&gt; which encapsulates the logic for processing the Lex request.  These have been separated out into modules to allow individual unit testing.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;line 24&lt;/em&gt; is where we are calling the dispatcher to process the request, we pass to this the reference to the slack client, again separating dependency and increasing testability.&lt;/p&gt;

&lt;h3 id=&quot;filesrcdispatcherjs&quot;&gt;file://src/dispatcher.js&lt;/h3&gt;
&lt;p&gt;Looking at the file &lt;em&gt;src/dispatcher.js&lt;/em&gt; we export a single function which is the one we are calling from our main handler.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; &lt;span class=&quot;mi&quot;&gt;84&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/**
 85 * Called when the user specifies an intent for this skill.
 86 */&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;87&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dispatch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;88&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`dispatch userId=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, intent=&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentIntent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;89&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentIntent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;91&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;92&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'WhatTimezone'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;93&lt;/span&gt;     &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;intentRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;currentIntent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;slots&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;94&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;95&lt;/span&gt;     &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUserDetails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;96&lt;/span&gt;      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'PlainText'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Failed'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
 &lt;span class=&quot;mi&quot;&gt;98&lt;/span&gt;      
 &lt;span class=&quot;mi&quot;&gt;99&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Fulfilled'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;101&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timezone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;102&lt;/span&gt;          &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' is in '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;103&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;104&lt;/span&gt;          &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Sorry I can&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;t find user: '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;105&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;106&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;107&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;error: &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;108&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;109&lt;/span&gt;      
&lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;111&lt;/span&gt;        &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;112&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;113&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;114&lt;/span&gt;        &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;115&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;     
&lt;span class=&quot;mi&quot;&gt;116&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;117&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;118&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;`Intent with name &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; not supported`&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The request that is sent to the function from Lex looks something like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;currentIntent&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;slots&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;User&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nicjackson&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;WhereIs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;confirmationStatus&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;None&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bot&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;alias&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$LATEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$LATEST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SlackBot&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;userId&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;John&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;invocationSource&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;DialogCodeHook&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;outputDialogMode&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Text&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;messageVersion&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;sessionAttributes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As we mentioned in the first section, Lex has the capability to extract information from the request and to include it in &lt;em&gt;slots&lt;/em&gt; passed as an object to your function.
The first thing we are doing in our function is to determine if this Lambda function can handle the intent.  On &lt;em&gt;line 92&lt;/em&gt; we are checking this; it is not necessary to perform this check however it could save some headaches if you accidentally wire the wrong function to an Intent.
We then call the slack client on &lt;em&gt;line 95&lt;/em&gt; and pass a callback which crafts the response to send back to Lex.  The main part of this code to note is &lt;em&gt;line 110&lt;/em&gt;, in this instance, we are sending back a &lt;em&gt;Close&lt;/em&gt; response to Lex, this sends the message that the response is final and no further interaction takes place for this session.  Other valid values are &lt;em&gt;ElicitSlot&lt;/em&gt; and &lt;em&gt;ConfirmIntent&lt;/em&gt;, the example code has helper functions which can craft the correct responses however for the purpose of simplicity we are only using the close function in this walkthrough.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sessionAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fulfillmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;responseCard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;34&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;sessionAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;        &lt;span class=&quot;na&quot;&gt;dialogAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;37&lt;/span&gt;            &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Close'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;            &lt;span class=&quot;nx&quot;&gt;fulfillmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;39&lt;/span&gt;            &lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;            &lt;span class=&quot;nx&quot;&gt;responseCard&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;41&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;43&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;sessionAttributes&lt;/em&gt; are what Lex uses to pass between client and code as it does not log and store these values.  A &lt;em&gt;responseCard&lt;/em&gt; if used is passed back to slack and can be used in addition to the message to request further information in the form of lists to prompt the user for action.  For example, in our application, if we do not find the user mentioned we could send back a list of possible matches, and the user could then click on this item rather than having to type the response.
&lt;em&gt;fulfillmentState&lt;/em&gt; is a string variable which contains the options of &lt;em&gt;“Fulfilled”&lt;/em&gt; or &lt;em&gt;“Failed”&lt;/em&gt;.
Moreover, the message is an object with the syntax:&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;contentType&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'PlainText'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;     &lt;span class=&quot;s1&quot;&gt;'Some content'&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;filesrcdispatchertestjs&quot;&gt;file://src/dispatcher.test.js&lt;/h3&gt;
&lt;p&gt;As an investigation into the workflow for building lambda functions with JavaScript, I have configured a couple of tests for the dispatcher which is the most complicated part of the function.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dispatch'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'calls the slack API with unknown user'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mockSlack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;      &lt;span class=&quot;na&quot;&gt;getUserDetails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;        &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;    &lt;span class=&quot;nx&quot;&gt;dispatcher&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dispatch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;intentStub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mockSlack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialogAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fulfillmentState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Fulfilled'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialogAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toBeDefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;outcome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;dialogAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toEqual&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'Sorry I can&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;t find user: nicjackson'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;30&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;    
&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Using dependency injection on our dispatcher, we can isolate the slack client giving us the capability to unit test the dispatcher.  Jest provides some nice matchers for the assertions and if needed also has a comprehensive mocking framework.    These tests are by no mean comprehensive or fully covering but they do indicate that it is possible to write Lambda TDD style, and with good test coverage can make up for the inability to easily run locally.  The serverless framework does provide the capability to run in &lt;em&gt;dev&lt;/em&gt; mode, but my opinion is that by removing this crutch you are pushed to producing a high-quality test suite which carries far greater benefit with long term maintenance.&lt;/p&gt;

&lt;h3 id=&quot;filesrcslackjs&quot;&gt;file://src/slack.js&lt;/h3&gt;
&lt;p&gt;Our slack client is fairly straight forward and makes a call to the &lt;em&gt;users.list&lt;/em&gt; endpoint on the slack API, iterates over the list and selects the timezone for the matching user.  At the time of writing, there was no way to directly retrieve a slack user using the API with only having the name of the user, not the ID.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;mi&quot;&gt;01&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*jslint node: true */&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;02&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/*jslint esversion: 6 */&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;03&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'use strict'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;04&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;05&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'@slack/client'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;WebClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;06&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;SLACK_API_KEY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;07&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;08&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;09&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getUserDetails&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;web&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;slackClient&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;  &lt;span class=&quot;nx&quot;&gt;web&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt;     &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;       &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;timezone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt;      &lt;span class=&quot;nx&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;members&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt;         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;           &lt;span class=&quot;nx&quot;&gt;timezone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tz_label&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;         &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;       
&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;timezone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;       &lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;26&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;mi&quot;&gt;28&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The main thing to note in this function is that we need the slack API token which is set in the Lambda setup when we deploy the function.&lt;/p&gt;

&lt;h2 id=&quot;step-2-deploying-the-lambda-function&quot;&gt;Step 2: Deploying the Lambda function&lt;/h2&gt;
&lt;p&gt;To deploy the lambda function uses Terraform by HashiCorp, the config for the deployment is found in the terraform folder.
For this, to work, we need valid AWS credentials and the Slack API token set to an environment variables on your machine.  I recommend using direnv and a .encrc file to manage this rather than setting the variables globally.  The variables which we need to set are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;AWS_ACCESS_KEY&lt;/strong&gt;  - Your aws access key for the account&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;AWS_SECRET_ACCESS_KEY&lt;/strong&gt; - The secret which corresponds to your access key&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;TF_VAR_SLACK_API_KEY&lt;/strong&gt; - A valid API token which can read the users details in slack&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;fileterraformlambdatf&quot;&gt;file://terraform/lambda.tf&lt;/h3&gt;
&lt;p&gt;If we take a look at the &lt;em&gt;terraform/lambda.tf&lt;/em&gt; we will see that we are defining a IAM role and policy for lambda which allows Lambda to write to the CloudWatch logs.  We are also creating an &lt;code class=&quot;highlighter-rouge&quot;&gt;aws_lambda_function&lt;/code&gt; resource.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;resource &quot;aws_lambda_function&quot; &quot;default&quot; {
  s3_bucket        = &quot;${aws_s3_bucket.default.id}&quot;
  runtime          = &quot;nodejs4.3&quot;
  function_name    = &quot;${var.lambda_function_name}&quot;
  role             = &quot;${aws_iam_role.iam_for_lambda.arn}&quot;
  handler          = &quot;index.handler&quot;
  s3_key           = &quot;${aws_s3_bucket_object.default.id}&quot;
  source_code_hash = &quot;${data.archive_file.lambdazip.output_md5}&quot;

  environment = {
    variables = {
      SLACK_API_KEY = &quot;${var.slack_api_key}&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;s3_bucket&lt;/strong&gt; is the s3 bucket where our application code is stored, and the value of this is a reference to another bit of Terraform config.&lt;br /&gt;
&lt;strong&gt;runtime&lt;/strong&gt; is specifying that we would like to use the &lt;em&gt;nodejs4.3&lt;/em&gt; runtime for lambda. &lt;br /&gt;
&lt;strong&gt;function_name&lt;/strong&gt; this is the name we would like to call our lambda function which is set in the file &lt;em&gt;terraform/terraform.tfvars&lt;/em&gt; also, has a value of &lt;em&gt;slackbot&lt;/em&gt;.&lt;br /&gt;
&lt;strong&gt;role&lt;/strong&gt; this is the IAM role that we created earlier in the config.&lt;br /&gt;
&lt;strong&gt;s3_key&lt;/strong&gt; this is the id of the zip file that we have uploaded to s3 which contains our source code.
&lt;strong&gt;source_code_hash&lt;/strong&gt; this is the hash code of our uploaded zip file, should we change the contents of the source code then this hash will be different and triggers a deployment of a new version.&lt;br /&gt;
&lt;strong&gt;environment&lt;/strong&gt; for our application to function we need a slack API key, and for simplicity, we are adding this to the environment variables.  It is important to note that it is possible to encrypt this using KMS however we are storing this plain text.&lt;/p&gt;

&lt;h3 id=&quot;fileterraforms3tf&quot;&gt;file://terraform/s3.tf&lt;/h3&gt;
&lt;p&gt;This file contains the terraform config to create an s3 bucket where our source code lives and also creates the archive and ensures that upon deploying, the archive is added to the bucket.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;data &quot;archive_file&quot; &quot;lambdazip&quot; {
  type        = &quot;zip&quot;
  source_dir  = &quot;${path.module}/../_build&quot;
  output_path = &quot;${path.module}/../lambda.zip&quot;
}

resource &quot;aws_s3_bucket&quot; &quot;default&quot; {
  bucket = &quot;${var.s3_bucket_name}&quot;
  acl    = &quot;private&quot;

  tags {
    Name        = &quot;${var.s3_bucket_name}&quot;
    Environment = &quot;Development&quot;
  }
}

resource &quot;aws_s3_bucket_object&quot; &quot;default&quot; {
  bucket = &quot;${aws_s3_bucket.default.bucket}&quot;
  key    = &quot;slackbot&quot;
  source = &quot;${path.module}/../lambda.zip&quot;
  etag   = &quot;${data.archive_file.lambdazip.output_md5}&quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can use a data element &lt;code class=&quot;highlighter-rouge&quot;&gt;archive_file&lt;/code&gt; which will create a zip archive for us when terraform runs.  We are setting the paths for the &lt;em&gt;source_dir&lt;/em&gt; which is the folder created when we run &lt;code class=&quot;highlighter-rouge&quot;&gt;make build, &lt;/code&gt; and the output is a file called lambda.zip in our source code root.&lt;br /&gt;
Terraform also has the capability to create an s3 bucket for us, if you already have a bucket that you would like to use then you can skip this resource element and directly add the arn to the bucket attribute of the &lt;code class=&quot;highlighter-rouge&quot;&gt;aws_s3_bucket&lt;/code&gt; stanza.  If already have an S3 bucket you would like to use for your source code remember that it must exist in the &lt;em&gt;us-east-1&lt;/em&gt; zone until Lex is rolled out across the other zones in AWS.&lt;/p&gt;

&lt;h3 id=&quot;deploying-the-function&quot;&gt;Deploying the function&lt;/h3&gt;
&lt;p&gt;To deploy the function we can run:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make package
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;make deploy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These commands install the yarn dependencies for testing and then run the &lt;em&gt;test&lt;/em&gt;, &lt;em&gt;build&lt;/em&gt;, and &lt;em&gt;deploy&lt;/em&gt; steps, the deploy step simply runs &lt;code class=&quot;highlighter-rouge&quot;&gt;terraform plan &amp;amp;&amp;amp; terraform apply&lt;/code&gt; .  The packaging step only needs to be run once or when you would like to update &lt;em&gt;jest&lt;/em&gt;.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;package:
  cd src &amp;amp;&amp;amp; yarn install
test:
    cd src &amp;amp;&amp;amp; yarn run jest

clean:
    rm -rf _build

build: clean
    mkdir _build
    cp src/index.js _build/
    cp src/dispatcher.js _build/
    cp src/slack.js _build/
    npm install --prefix=_build @slack/client

deploy: test build
    cd terraform &amp;amp;&amp;amp; terraform plan
    cd terraform &amp;amp;&amp;amp; terraform apply
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will see some output on the command line:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;src &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; yarn run jest                                                                                                                                                                                                                                                                    yarn run v0.22.0                                                                                                                                                                                                                                                                           &lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/Users/nicj/Developer/lambda/slack-bot/src/node_modules/.bin/jest&quot;&lt;/span&gt;                                                                                                                                                                                                                       PASS  ./dispatcher.test.js                                                                                                                                                                                                                                                                  dispatch                                                                                                                                                                                                                                                                                     ✓ calls the slack API with unknown user &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;4ms&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                                                                                                                                                                                                                                              ✓ calls the slack API with known user &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;1ms&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;                                                                                                                                                                                                                                                ✓ returns error when error from slack API                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         Test Suites: 1 passed, 1 total                                                                                                                                                                                                                                                             Tests:       3 passed, 3 total                                                                                                                                                                                                                                                             Snapshots:   0 total                                                                                                                                                                                                                                                                       Time:        0.539s, estimated 1s                                                                                                                                                                                                                                                          Ran all &lt;span class=&quot;nb&quot;&gt;test &lt;/span&gt;suites.                                                                                                                                                                                                                                                                         console.log dispatcher.js:88                                                                                                                                                                                                                                                                 dispatch &lt;span class=&quot;nv&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;undefined, &lt;span class=&quot;nv&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WhereIs                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           console.log dispatcher.js:88
    dispatch &lt;span class=&quot;nv&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;undefined, &lt;span class=&quot;nv&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WhereIs

  console.log dispatcher.js:88
    dispatch &lt;span class=&quot;nv&quot;&gt;userId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;undefined, &lt;span class=&quot;nv&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;WhereIs

  console.log dispatcher.js:107
    error: Something went wrong
                                                                                                                                                                                                                                                                                           ✨  Done &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;1.01s.

...

Apply &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; Resources: 0 added, 1 changed, 0 destroyed.

The state of your infrastructure has been saved to the path
below. This state is required to modify and destroy your
infrastructure, so keep it safe. To inspect the &lt;span class=&quot;nb&quot;&gt;complete &lt;/span&gt;state
use the &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;terraform show&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt; command.

State path:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you take a look at your AWS Lambda dashboard (N.Virginia) you should now see a new function and we can begin to configure Lex and Slack.&lt;/p&gt;

&lt;h2 id=&quot;step-3-configuring-aws-lex-and-slack&quot;&gt;Step 3 Configuring AWS Lex and Slack&lt;/h2&gt;
&lt;ol&gt;
  &lt;li&gt;Sign in to the AWS Management Console and open the Amazon Lex console at https://console.aws.amazon.com/lex/.&lt;/li&gt;
  &lt;li&gt;Click the &lt;em&gt;Create&lt;/em&gt; button and choose &lt;em&gt;Custom Bot&lt;/em&gt; fill in the details and then press Create.
&lt;img src=&quot;/images/posts/slackbot/create.png&quot; alt=&quot;create&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Click &lt;em&gt;Create intent&lt;/em&gt; and the &lt;em&gt;Create new Intent&lt;/em&gt;&lt;br /&gt;
&lt;img src=&quot;/images/posts/slackbot/createintent.png&quot; alt=&quot;create intent&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;Enter the title of the intent “WhatTimezone” and press &lt;em&gt;Create&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Add the utterances “What timezone is {User} in” and the slots &lt;em&gt;User&lt;/em&gt; which has the type &lt;em&gt;AMAZON.Person&lt;/em&gt;.  Select our lambda function in the &lt;em&gt;Fulfillment&lt;/em&gt; section and then save the intent.&lt;/li&gt;
  &lt;li&gt;To test our bot we need to build it so press the &lt;em&gt;Build&lt;/em&gt; button in the top right-hand corner, the test window will then pop up and you can test your bot is working before connecting it to slack.  If you have called your Intent something different to “WhatTimezone” then you need to update the code in &lt;em&gt;src/dispatcher.js&lt;/em&gt; accordingly.&lt;br /&gt;
&lt;img src=&quot;/images/posts/slackbot/testbot.png&quot; alt=&quot;test&quot; /&gt;&lt;/li&gt;
  &lt;li&gt;We can now publish the function by pressing the &lt;em&gt;Publish&lt;/em&gt; button in the top right-hand corner and proceed to configure Slack.&lt;/li&gt;
  &lt;li&gt;The default instructions from AWS are just fine for configuring slack, so rather than reproduce them verbatim I encourage you to follow steps 3 through 6 in the following guide.  &lt;a href=&quot;http://docs.aws.amazon.com/lex/latest/dg/slack-bot-association.html&quot;&gt;http://docs.aws.amazon.com/lex/latest/dg/slack-bot-association.html&lt;/a&gt;.   One important thing to note is that when you are setting up your channel you will be asked for a &lt;em&gt;Verification Token&lt;/em&gt;, Slack only shows the &lt;em&gt;Verification&lt;/em&gt; token on the &lt;em&gt;Basic Information&lt;/em&gt; screen once you have added an &lt;em&gt;Event Subscription&lt;/em&gt; however until you add the verification token AWS will not give you the URL.  To get round this click on &lt;em&gt;Event Subscriptions&lt;/em&gt; enter any URL and once you have a verification failed message again click on &lt;em&gt;Basic Information&lt;/em&gt;.
&lt;img src=&quot;/images/posts/slackbot/appcredentials.png&quot; alt=&quot;app credentials&quot; /&gt;
&lt;img src=&quot;/images/posts/slackbot/eventsubscription.png&quot; alt=&quot;event subscription&quot; /&gt;
&lt;img src=&quot;/images/posts/slackbot/appcredentials2.png&quot; alt=&quot;app credentials&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;step-4-testing-in-slack&quot;&gt;Step 4 testing in Slack&lt;/h2&gt;
&lt;p&gt;Once everything has been configured, you can then go to your slack team invite the slackbot you have just created to the channel and then when you write a message like “What timezone is nicjackson in?”, the bot should reply with the correct answer.
&lt;img src=&quot;/images/posts/slackbot/slack.png&quot; alt=&quot;test&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;
&lt;p&gt;This example is only a simple based on some investigation I did at the weekend into Lex; however, it has been quite fun, and I will certainly continue to work on this and add more advanced functionality.  All the resources and links for this talk are listed below, and if you need any assistance, I can be found on Twitter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source Code:&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://github.com/nicholasjackson/slack-bot-lex-lambda&quot;&gt;https://github.com/nicholasjackson/slack-bot-lex-lambda&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Lex Developer Guide:&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;http://docs.aws.amazon.com/lex/latest/dg/what-is.html&quot;&gt;http://docs.aws.amazon.com/lex/latest/dg/what-is.html&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Lex Input and Response Format:&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;http://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html&quot;&gt;http://docs.aws.amazon.com/lex/latest/dg/lambda-input-response-format.html&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Terraform:&lt;/strong&gt; &lt;br /&gt;
&lt;a href=&quot;http://www.terraform.io&quot;&gt;https://www.terraform.io&lt;/a&gt;&lt;br /&gt;
&lt;strong&gt;Jest:&lt;/strong&gt;&lt;br /&gt;
&lt;a href=&quot;https://facebook.github.io/jest/&quot;&gt;https://facebook.github.io/jest/&lt;/a&gt;&lt;/p&gt;
</description>
        <pubDate>Tue, 25 Apr 2017 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2017/04/25/slack-bot-aws-lambda/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2017/04/25/slack-bot-aws-lambda/</guid>
        
        <category>bots</category>
        
        <category>serverless</category>
        
        <category>slack</category>
        
        <category>node</category>
        
        <category>lex</category>
        
        <category>terraform</category>
        
        
      </item>
    
      <item>
        <title>Configuring API Gateway for GraphQL Lambda functions</title>
        <description>&lt;p&gt;This is a short post which hopefully will explain a few gotchas when setting up a GraphQL endpoint with AWS Lambda.&lt;/p&gt;

&lt;p&gt;The main problem is not Lambda per-se it is actually API Gateway which sits in front of Lambda.  By default API
Gateway expects input and output type of &lt;em&gt;application/json&lt;/em&gt; and this is fine except when you send a POST request which contains a data payload in the format of &lt;em&gt;application/graphql&lt;/em&gt;.  The best practice document on the GraphQL website &lt;a href=&quot;http://graphql.org/learn/serving-over-http/&quot;&gt;http://graphql.org/learn/serving-over-http/&lt;/a&gt; recommends that a POST request should enable both requests in application/json format and in application/graphql.&lt;/p&gt;

&lt;p&gt;If you try to send a query in graphql format to API Gateway like the following:&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;curl -i -XPOST -H 'Content-Type: application/graphql' -d '{ products { code } }' http://myendpoint.com/prod
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You will find that you get an error message like the following:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/1.1 400 Bad Request
 Content-Type: application/json
 Content-Length: 189
 Connection: keep-alive
 Date: Tue, 13 Dec 2016 11:04:31 GMT
 x-amzn-RequestId: eca43820-c123-11e6-8b65-53d711979cac
 X-Cache: Error from cloudfront
 Via: 1.1 92423f766303b20998ffc97d623638f7.cloudfront.net (CloudFront)
 X-Amz-Cf-Id: MZVqwhSakST3qG4B_lKoGVuDdBvtwJfY4hkamF8pgDN-bb6S9e5ERg==
 
 {&quot;message&quot;: &quot;Could not parse request body into json: Unexpected character (\'p\' (code 112)): was expecting double-quote to start field name\n at [Source: [B@77acd1ac; line: 1, column: 4]&quot;}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is due to API Gateway attempting to convert our post body into JSON, which it clearly is not.&lt;/p&gt;

&lt;h2 id=&quot;how-to-fix-this&quot;&gt;How to fix this&lt;/h2&gt;
&lt;p&gt;To fix this problem we need to make some changes to the API Gateway configuration.&lt;/p&gt;

&lt;h3 id=&quot;step-1-enable-binary-support&quot;&gt;Step 1: Enable Binary Support&lt;/h3&gt;
&lt;p&gt;The first thing we need to do is to enable binary support, if you click the &lt;em&gt;Binary Support&lt;/em&gt; menu item you will be presented with a screen which allows you to tell API Gateway to treat payloads associated with certain media types as binary data.  This means that it will not attempt to convert the payload to JSON.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/graphql/binary_support.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If we add our &lt;em&gt;application/graphql&lt;/em&gt; media type and re-deploy the API you will see that we are now getting a slightly different error message.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/1.1 400 Bad Request
 Content-Type: application/json
 Content-Length: 203
 Connection: keep-alive
 Date: Tue, 13 Dec 2016 11:14:14 GMT
 x-amzn-RequestId: 47d5bff1-c125-11e6-aef0-459b4e1c48a4
 X-Cache: Error from cloudfront
 Via: 1.1 92423f766303b20998ffc97d623638f7.cloudfront.net (CloudFront)
 X-Amz-Cf-Id: xoaKYlLZg866CwA14f3p0u5N15sYxQcwiowCy1sdm9HDsmIFp0oxhw==
 
 {&quot;message&quot;: &quot;Could not parse request body into json: Unrecognized token \'eyBwcm9kdWN0cyB7IGNvZGUgfSB9\': was expecting (\'true\', \'false\' or \'null\')\n at [Source: [B@68df8622; line: 1, column: 57]&quot;}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-2-add-a-mapping-template&quot;&gt;Step 2: Add a mapping template&lt;/h3&gt;
&lt;p&gt;Just adding binary support is not enough, API Gateway is still attempting to parse the data into JSON however this is now happening in a later stage of the request, if you  click on your resource and look at the Method Execution flow you should have an &lt;em&gt;Integration Request&lt;/em&gt; item.  Clicking on this will take you to the following screen and expanding the &lt;em&gt;Body Mapping Templates&lt;/em&gt; section we need to add a new template.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/graphql/body_mapping_template.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Add a mapping template for the content type &lt;em&gt;application/graphql&lt;/em&gt; and then configure your template by adding the following code.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{ &quot;query&quot;: &quot;$util.base64Decode($input.body)&quot; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This transforms the input into the output with the following structure.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;{
  &quot;query&quot;: &quot;{ products { code title } }&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we use the binary support our request body represented by &lt;em&gt;$input.body&lt;/em&gt; is stored as a base64 encoded string.  We can use the utility function &lt;em&gt;base64Decode(string)&lt;/em&gt; to transform this back into a string.  Lambda is still expecting a Payload in JSON format by using the mapping template we can take our input and wrap this into a format that the lambda function is happy with.&lt;/p&gt;

&lt;p&gt;Now again deploy the API and re-test.&lt;/p&gt;

&lt;p&gt;You should see your data now returning as requested.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;HTTP/1.1 200 OK
 Content-Type: application/json
 Content-Length: 1622
 Connection: keep-alive
 Date: Tue, 13 Dec 2016 11:34:07 GMT
 x-amzn-RequestId: 0c943239-c128-11e6-94b6-7967c2010156
 X-Amzn-Trace-Id: Root=1-584fdcab-b22f22b3fe1fc4d5323d71c1
 X-Cache: Miss from cloudfront
 Via: 1.1 be27f8aa8af4ef7f3d1f074ecbf3b266.cloudfront.net (CloudFront)
 X-Amz-Cf-Id: NDfYQ70rUlqMrJt-_gjRMBCYDEj5eED7JM8bPCkFMRb7ZGXoWgmiFQ==
 
 {&quot;data&quot;:{&quot;products&quot;:[{&quot;code&quot;:176176},{&quot;code&quot;:465956},{&quot;code&quot;:277748}]}}%
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One thing to note is that your lambda function must be returning the content type as &lt;em&gt;application/json&lt;/em&gt; if it is not you might find that instead of returning JSON API Gateway wraps your output in a string which will most likely break things.&lt;/p&gt;

</description>
        <pubDate>Tue, 13 Dec 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/12/13/using-graphql-with-aws-lambda/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/12/13/using-graphql-with-aws-lambda/</guid>
        
        <category>serverless</category>
        
        <category>graphql</category>
        
        
      </item>
    
      <item>
        <title>Building microservices with Swift : Part 1 of 3</title>
        <description>&lt;h1 id=&quot;post-coming-soon&quot;&gt;POST COMING SOON&lt;/h1&gt;
</description>
        <pubDate>Wed, 07 Dec 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/12/07/building-microservices-with-swift-1/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/12/07/building-microservices-with-swift-1/</guid>
        
        <category>microservices</category>
        
        <category>swift</category>
        
        
      </item>
    
      <item>
        <title>What makes a good microservice framework</title>
        <description>&lt;p&gt;This is of course an entirely subjective opinion for most people however whilst I have been thinking about this and how it could be possible to score and rank the various frameworks I thought I would share a mind map I have made.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/images/posts/good-frameworks/mindmap_large.png&quot;&gt;&lt;img src=&quot;/images/posts/good-frameworks/mindmap.png&quot; alt=&quot;MindMap&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;ease-of-use&quot;&gt;Ease of use?&lt;/h2&gt;
&lt;p&gt;The first category I wanted to look at was the Ease of use, any good framework should be easy to use, this category has been broken down into the following sub categories.&lt;/p&gt;

&lt;h3 id=&quot;fast-setup&quot;&gt;Fast setup&lt;/h3&gt;
&lt;p&gt;The framework should be fast to setup and with the minimum number of steps and dependencies.&lt;/p&gt;

&lt;h3 id=&quot;code-generation&quot;&gt;Code generation&lt;/h3&gt;
&lt;p&gt;It should support code generation templates to scaffold an initial service and possibly extend the service.&lt;/p&gt;

&lt;h3 id=&quot;tooling&quot;&gt;Tooling&lt;/h3&gt;
&lt;p&gt;There must be adequate tooling.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;CI/CD: Must integrate and work well with Continuous Integration and Continuous Deployment pipelines.  The tooling must be scriptable from bash.&lt;/li&gt;
  &lt;li&gt;Cross platform: The tools must work cross platform, Mac and Linux as a bare minimum.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;maintainable&quot;&gt;Maintainable&lt;/h3&gt;
&lt;p&gt;The framework must be maintainable with the minimum of effort.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Easy to update: It must be easy to update with the minimum of code changes.&lt;/li&gt;
  &lt;li&gt;Well versioned: The framework must be well versioned with breaking changes to the API mainly restricted to Major version updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;format&quot;&gt;Format&lt;/h2&gt;
&lt;p&gt;Ideally the service will support good standards in one of the following formats.&lt;/p&gt;

&lt;h3 id=&quot;rest&quot;&gt;REST&lt;/h3&gt;
&lt;p&gt;If the framework implements REST it must take full advantage of semantic API design with appropriate use of HTTP verbs and Status Codes.&lt;/p&gt;

&lt;h3 id=&quot;rpc&quot;&gt;RPC&lt;/h3&gt;
&lt;p&gt;If the framework is RPC based it must use a standard and open messaging protocol.&lt;/p&gt;

&lt;h2 id=&quot;patterns&quot;&gt;Patterns&lt;/h2&gt;
&lt;p&gt;The framework must implement the standard patterns of microservice architecture.&lt;/p&gt;

&lt;h3 id=&quot;circuit-breaking&quot;&gt;Circuit breaking&lt;/h3&gt;
&lt;p&gt;Client calls to downstream services must implement circuit breaking.&lt;/p&gt;

&lt;h3 id=&quot;service-discovery&quot;&gt;Service discovery&lt;/h3&gt;
&lt;p&gt;It must be capable of registering with a dynamic service registry and capable of querying the same registry to locate connected services.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Consul&lt;/li&gt;
  &lt;li&gt;Etcd&lt;/li&gt;
  &lt;li&gt;DNS SRV records&lt;/li&gt;
  &lt;li&gt;Proprietory: Proprietary service registries must be open and usable from other clients which do no implement the framework or its SDKs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;timeouts&quot;&gt;Timeouts&lt;/h3&gt;
&lt;p&gt;Downstream client calls must be equipped with a user configurable timeout.&lt;/p&gt;

&lt;h3 id=&quot;health-checks&quot;&gt;Health checks&lt;/h3&gt;
&lt;p&gt;The framework must create an automatic health check endpoint.&lt;/p&gt;

&lt;h3 id=&quot;routing&quot;&gt;Routing&lt;/h3&gt;
&lt;p&gt;The framework must support multiple routes with an easy to use pattern based matching.&lt;/p&gt;

&lt;h3 id=&quot;middleware&quot;&gt;Middleware&lt;/h3&gt;
&lt;p&gt;The framework must support middleware to allow the user to create shared code for handlers.&lt;/p&gt;

&lt;h3 id=&quot;load-balancing&quot;&gt;Load balancing&lt;/h3&gt;
&lt;p&gt;Downstream client connections should be capable of load balancing.&lt;/p&gt;

&lt;h2 id=&quot;language-independence&quot;&gt;Language independence&lt;/h2&gt;
&lt;p&gt;The framework needs to be language independent to enable cross team polyglot workflow.&lt;/p&gt;

&lt;h3 id=&quot;polyglot&quot;&gt;Polyglot&lt;/h3&gt;
&lt;p&gt;At a minimum it should be possible to create client SDKs in multiple languages.&lt;/p&gt;

&lt;h2 id=&quot;ability-to-interface-with-other-frameworks&quot;&gt;Ability to interface with other frameworks&lt;/h2&gt;
&lt;p&gt;It must be possible to interact with any service built with the framework by clients who are not built using the same framework.&lt;/p&gt;

&lt;h3 id=&quot;implements-standards&quot;&gt;Implements standards&lt;/h3&gt;
&lt;p&gt;A standard message protocol should be used to maximize interaction.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;JSON-RPC&lt;/li&gt;
  &lt;li&gt;Thrift&lt;/li&gt;
  &lt;li&gt;Protobuffers&lt;/li&gt;
  &lt;li&gt;JSON&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;open&quot;&gt;Open&lt;/h3&gt;
&lt;p&gt;The framework should be open in both the source code and the roadmap.&lt;/p&gt;

&lt;h2 id=&quot;extensible&quot;&gt;Extensible&lt;/h2&gt;
&lt;p&gt;When required the user should be able to extend the framework.&lt;/p&gt;

&lt;h3 id=&quot;plugins&quot;&gt;Plugins&lt;/h3&gt;
&lt;p&gt;A pluggable software architecture to be able to create generators and templates.&lt;/p&gt;

&lt;h3 id=&quot;middleware-1&quot;&gt;Middleware&lt;/h3&gt;
&lt;p&gt;Extension through handler middleware.&lt;/p&gt;

&lt;h2 id=&quot;support&quot;&gt;Support&lt;/h2&gt;
&lt;p&gt;A good support network is incredibly important throughout the lifecycle of the service.&lt;/p&gt;

&lt;h3 id=&quot;maintained&quot;&gt;Maintained&lt;/h3&gt;
&lt;p&gt;The framework should be well maintained with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Regular updates&lt;/li&gt;
  &lt;li&gt;Accepts pull requests&lt;/li&gt;
  &lt;li&gt;Corporate sponsor: Whilst this option is not essential a corporate sponsor can extend the lifecycle of a framework as there is less likelihood of a  [leftpad] situation.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;documentation&quot;&gt;Documentation&lt;/h3&gt;
&lt;p&gt;The framework should be well documented with clear and concise examples and comprehensive API documentation.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Easy to follow: Documentation should be accessible and easy to read.&lt;/li&gt;
  &lt;li&gt;Code samples: Adequate code samples should be provided to support a developer using the framework.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;tutorials&quot;&gt;Tutorials&lt;/h3&gt;
&lt;p&gt;The framework will ideally have community contributed tutorials in both blog and video formats.&lt;/p&gt;

&lt;h3 id=&quot;community&quot;&gt;Community&lt;/h3&gt;
&lt;p&gt;There should be a good community using and supporting the framework with at least one of the following channels of communication.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Slack&lt;/li&gt;
  &lt;li&gt;Gitter&lt;/li&gt;
  &lt;li&gt;Github&lt;/li&gt;
  &lt;li&gt;Mailing list&lt;/li&gt;
  &lt;li&gt;Stack Overflow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;secure&quot;&gt;Secure&lt;/h2&gt;
&lt;p&gt;The framework should be secure and implement the latest industry standards.&lt;/p&gt;

&lt;h3 id=&quot;tls&quot;&gt;TLS&lt;/h3&gt;
&lt;p&gt;It should be possible to secure the endpoints of the framework using TLS.&lt;/p&gt;

&lt;h3 id=&quot;owasp&quot;&gt;OWASP&lt;/h3&gt;
&lt;p&gt;The framework should implement OWASP advisory.&lt;/p&gt;

&lt;h3 id=&quot;validation&quot;&gt;Validation&lt;/h3&gt;
&lt;p&gt;Requests should be automatically validated based on rules implemented by message annotation.&lt;/p&gt;

&lt;h3 id=&quot;well-patched&quot;&gt;Well patched&lt;/h3&gt;
&lt;p&gt;Security vulnerabilities should be regularly assessed and patched.&lt;/p&gt;

&lt;h2 id=&quot;open-source&quot;&gt;Open source&lt;/h2&gt;
&lt;p&gt;The framework should be open sourced and released on a license which allows forking and modification.&lt;/p&gt;

&lt;h3 id=&quot;community-1&quot;&gt;Community&lt;/h3&gt;
&lt;p&gt;There should be good open source community following and contribution for the project.&lt;/p&gt;

&lt;h3 id=&quot;popular&quot;&gt;Popular&lt;/h3&gt;
&lt;p&gt;The framework should be popular and commercially used.&lt;/p&gt;

&lt;h2 id=&quot;quality&quot;&gt;Quality&lt;/h2&gt;
&lt;p&gt;The code quality of the service should be visible and of a high standard. Community contributions should follow a published process and standard.&lt;/p&gt;

&lt;h3 id=&quot;high-test-coverage&quot;&gt;High test coverage&lt;/h3&gt;
&lt;p&gt;Test coverage should be high and monitored, pull requests should ensure adherence to coding standards.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Unit
High number of fast running unit tests is essential for both the framework and the generated code.&lt;/li&gt;
  &lt;li&gt;Behavioural / functional: Ideally the framework should implement behavioral and functional tests in terms of the generated code and the build process.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;automated-builds&quot;&gt;Automated builds&lt;/h3&gt;
&lt;p&gt;Automated builds of the source code should be present and visible.  Pull requests should run an automated build and the state reported on the request.&lt;/p&gt;

&lt;h3 id=&quot;code-quality&quot;&gt;Code quality&lt;/h3&gt;
&lt;p&gt;Automated code quality tools should be used and the results visible.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Coveralls&lt;/li&gt;
  &lt;li&gt;Code climate&lt;/li&gt;
  &lt;li&gt;Sonar&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;standard-language-patterns&quot;&gt;Standard language patterns&lt;/h3&gt;
&lt;p&gt;A standard method of writing the code taking account of the language level idioms is essential.&lt;/p&gt;

&lt;h2 id=&quot;efficient&quot;&gt;Efficient&lt;/h2&gt;
&lt;p&gt;The framework must produce code which is efficient when run.&lt;/p&gt;

&lt;h3 id=&quot;fast&quot;&gt;Fast&lt;/h3&gt;
&lt;p&gt;The code must execute quickly and be designed for performance.&lt;/p&gt;

&lt;h3 id=&quot;low-latency&quot;&gt;Low latency&lt;/h3&gt;
&lt;p&gt;Requests should be low latency.&lt;/p&gt;

&lt;h3 id=&quot;low-memory&quot;&gt;Low memory&lt;/h3&gt;
&lt;p&gt;The service should be memory efficient.&lt;/p&gt;

&lt;h3 id=&quot;supports-large-number-of-connections&quot;&gt;Supports large number of connections&lt;/h3&gt;
&lt;p&gt;It should support a large number of concurrent connections.&lt;/p&gt;
</description>
        <pubDate>Sun, 21 Aug 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/08/21/what-makes-a-good-microservice-framework/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/08/21/what-makes-a-good-microservice-framework/</guid>
        
        <category>microservices</category>
        
        <category>thoughts</category>
        
        
      </item>
    
      <item>
        <title>My struggles with RPC</title>
        <description>&lt;p&gt;I have decided to write up my thinking on some investigation I have done with gRPC and protobuffers. At first I hated the concept as I was fully entrenched in the “Why use anything other than REST” camp, however from playing round a little with gRPC I am starting to feel that RPC with a DSL for defining contracts with protobuffers could be the way to go.&lt;/p&gt;

&lt;p&gt;My argument for REST has always been the accessibility of it, however gRPC supports 10 languages from the official packages and many more from community packages.  The benefits of protobuffers are that you can generate a client in your chosen language using the protoc application, this allows DRYness of code across the many consumers of your API.  Sure you can use Swagger to define your API and then code gen from the Swagger files but this process defeats the purpose of defining an API in a RESTful way will all the semantics of HTTP verbs to infer intent.  If you are generating clients then why not take advantage of the efficiency of RPC based communication and also allow yourself the benefits of using light weight binary messaging.&lt;/p&gt;

&lt;h2 id=&quot;versioning&quot;&gt;Versioning:&lt;/h2&gt;
&lt;p&gt;No more complex than when working with REST, use semantic versioning can be implemented in the same way as you can in rest, gRPC is not like JMI where the exact same interface must be implemented on both the client and the server, you can add elements to the server side interface and by implementing the same standard rules you would follow with a RESTful API you are in a no worse position.&lt;/p&gt;

&lt;h3 id=&quot;breaking-changes-update-major-version-client-contract-update-required&quot;&gt;Breaking changes (update Major version, client contract update required):&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Removing or renaming APIs or API parameters;&lt;/li&gt;
  &lt;li&gt;Changing the type of an API parameter for example from Integer to String;&lt;/li&gt;
  &lt;li&gt;Changes to response codes, error codes or fault contracts;&lt;/li&gt;
  &lt;li&gt;Changes to the behavior of an existing API.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;things-that-do-not-involve-a-breaking-change-no-client-updated-required-unless-desired&quot;&gt;Things that do not involve a breaking change (No client updated required unless desired):&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Adding parameters to a returned entity;&lt;/li&gt;
  &lt;li&gt;Adding additional endpoints or functionality;&lt;/li&gt;
  &lt;li&gt;Bug fixes or other maintenance which do not included items in the breaking changes list.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;web-access&quot;&gt;Web access:&lt;/h2&gt;
&lt;p&gt;This is where RPC falls down however there is an architectural pattern called a HTML → RPC reverse proxy which is explained a little bit in this blog post: (http://www.grpc.io/blog/coreos)[http://www.grpc.io/blog/coreos]. Whilst this can seem like a problem it is restricted to your Public APIs.  Following the reverse proxy pattern you can easily create RESTful endpoints for browser based clients and support RPC for native apps.  Internal services can consume the RPC client with no problems.&lt;/p&gt;

&lt;h2 id=&quot;documentation&quot;&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Your proto files are the documentation, creating comments inside the file is all that is really needed,&lt;/p&gt;

&lt;div class=&quot;language-proto highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The greeting service definition.
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;service&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Users&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// Create user creates a user in the system with the given User details,
&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// it returns an Error message which will be nil on a successful operation
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;rpc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;CreateUser&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Person describes a user entity
&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;User&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// name is a required field and represents the name of
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// id is the unique identifier for the user in the system
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int32&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// email is the users email address and is an optional field 
&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;optional&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;optional&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int32&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;optional&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;detail&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

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

&lt;h2 id=&quot;advantages--disadvantages&quot;&gt;Advantages / Disadvantages&lt;/h2&gt;

&lt;h3 id=&quot;advantages&quot;&gt;Advantages&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Ability to easily implement one / two way streaming for data;&lt;/li&gt;
  &lt;li&gt;Auto generated client code;&lt;/li&gt;
  &lt;li&gt;Fast and low latency communication;&lt;/li&gt;
  &lt;li&gt;Native mobile clients get a huge boost by avoiding HTTP;&lt;/li&gt;
  &lt;li&gt;Fantastic open source support with gRPC, Thrift, JSON-RPC.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;disadvantages&quot;&gt;Disadvantages&lt;/h3&gt;
&lt;ul&gt;
  &lt;li&gt;Inability to leverage HTTP caching provided by a CDN;&lt;/li&gt;
  &lt;li&gt;Possibility of having to implement a reverse proxy to support browser based clients;&lt;/li&gt;
  &lt;li&gt;Testing, you can’t just CURL an endpoint and it may be required to build a test harness.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I will certainly be investigating gRPC and protobuffers further and can see myself using this as the defacto communication standard for my microservices.&lt;/p&gt;

&lt;h2 id=&quot;further-reading&quot;&gt;Further reading&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;gRPC Framework (http://www.grpc.io)[http://www.grpc.io]&lt;/li&gt;
  &lt;li&gt;Thrift Framework (https://thrift.apache.org)[https://thrift.apache.org]&lt;/li&gt;
  &lt;li&gt;JSON-RPC Standard (http://json-rpc.org)[http://json-rpc.org]&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 19 Aug 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/08/19/thoughts-on-rpc/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/08/19/thoughts-on-rpc/</guid>
        
        <category>microservices</category>
        
        <category>rpc</category>
        
        <category>thoughts</category>
        
        
      </item>
    
      <item>
        <title>You call that optimisation? This is optimisation!</title>
        <description>&lt;p&gt;Whilst writing a chapter for my book “Building Microservices in Go” I was working on a section for JSON parsing in Go.  As I was explaining the various semantics of the &lt;em&gt;encoding/json&lt;/em&gt; package I wrote a really simple example of using &lt;em&gt;json.Marshal&lt;/em&gt; to convert a struct into it most simple string representation.  In this example (see listing 1) I decoded the struct into a byte array and then wrote it to the response using &lt;em&gt;fmt.FPrint&lt;/em&gt;.  Not the code I would write in a handler but to explain the simple useage of the package before moving on to show how you can use the prefered method which are Encoders (see listing 2).&lt;/p&gt;

&lt;h3 id=&quot;listing-1&quot;&gt;listing 1&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkHelloHandlerVariable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResetTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                            
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Discard&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                               
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                              
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Marshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                 
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Fprint&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                  
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                                         
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                                                 
                                                                                                                                  
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;listing-2&quot;&gt;listing 2&lt;/h3&gt;
&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkHelloHandlerEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                 
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResetTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                            
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Discard&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                               
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                              
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                         
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                                         
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;          
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After writing this code I decided that I would have a quick look and see the inefficiencies between the first method and the second.  It turns out there is a 40% speed improvement in the second example.  This is mainly due to the fact that the using the encoder.Encode rather than copying the output from Marshal to a byte array dramatically reduces the number of memory allocations that the method has to perform from 5 to 2.&lt;/p&gt;

&lt;p&gt;If we optimise this further by passing a reference to the encoder rather than passing by value (see listing 3) we see further gains by 100 nanoseconds a 50% reduction over the first method, again this is because we are reducing the number of memory allocations performed.&lt;/p&gt;

&lt;h3 id=&quot;listing-3&quot;&gt;listing 3&lt;/h3&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BenchmarkHelloHandlerEncoderReference&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                 
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResetTimer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                            
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioutil&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Discard&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                               
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                              
                                                                                                                                  
        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;N&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewEncoder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                
                &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;encoder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Encode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                         
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                                                                                                                         
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;          
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;benchmarks&quot;&gt;benchmarks&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;go &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-run&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;none&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-bench&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-benchtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;5s&quot;&lt;/span&gt;  &lt;span class=&quot;nt&quot;&gt;-benchmem&lt;/span&gt;
testing: warning: no tests to run
PASS
BenchmarkHelloHandlerVariable           10000000              1187 ns/op             248 B/op          5 allocs/op
BenchmarkHelloHandlerEncoder            10000000               731 ns/op              24 B/op          2 allocs/op
BenchmarkHelloHandlerEncoderReference   10000000               660 ns/op               8 B/op          1 allocs/op
ok      github.com/nicholasjackson/building-microservices-in-go/chapter1/bench  28.394s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now these are tiny numbers but if this was the only operation that the server was performing then we could get away with half the hardware to satisfy the same load, that means saving money.&lt;/p&gt;

&lt;p&gt;I hope this has shown you that allocating memory does not come for free and that with a little thought and knowledge you can dramatically increase the speed of your application.  I would never advocate premature optimisation and there is none of this here, this is simply understanding that memory allocation takes time and if we can avoid it then we should.  It is also about using the right options that you already have available to you and to do that you need to understand your core language and framework.&lt;/p&gt;
</description>
        <pubDate>Sat, 23 Jul 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/07/23/thats-not-optimisation/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/07/23/thats-not-optimisation/</guid>
        
        <category>microservices</category>
        
        <category>go</category>
        
        
      </item>
    
      <item>
        <title>0 to Microservice in 5 minutes with Go and Minke</title>
        <description>&lt;h1 id=&quot;introduction&quot;&gt;Introduction&lt;/h1&gt;
&lt;p&gt;I went to a conference a few weeks ago which was angled at technology in the retail environment, by lunchtime nobody had mentioned the words “Docker” or “Microservices”, I made my excuses and got the hell out of there.  Everyone is talking about Microservices, even the bus driver the other day was complaining that the reason the bus was late was due to not enough monitoring in their scheduling microservice. Allegedly the wrong config was pushed to Consul, the service was failing and nobody knew.  OK so the last part might be made up but I bet a few of you will have felt that pain, those who have not, don’t worry, when it happens it will be OK.  Unless of course you work on nuclear missile launch systems and you accidental wipe out life for half the planet, that would not be OK, very not OK.&lt;/p&gt;

&lt;p&gt;The thing is that everyone is talking about microservices but the frameworks and development practices are not so mature yet, there are some amazing companies like Netflix and USwitch who have been using this stuff for a number of years but knowledge and patterns have only slowly seeped out into the mainstream.  Rails was not built in a day and it will be the same for a good microservice framework, there is some amazing stuff on the horizon but the key will be mass adoption and contribution.&lt;/p&gt;

&lt;p&gt;What I would like to show you in this post is how you can go from &lt;strong&gt;0 - Microservice in 5 minutes&lt;/strong&gt;, that’s scaffolding a new service building and testing locally then getting the build and test passing on CI.  I will assume that you have the &lt;strong&gt;Docker Toolkit&lt;/strong&gt;, &lt;strong&gt;Ruby&lt;/strong&gt; and &lt;strong&gt;Go&lt;/strong&gt; installed on your dev machine as otherwise that might take longer than 5 minutes and that would mess with the title of my post.&lt;/p&gt;

&lt;h2 id=&quot;frameworks&quot;&gt;Frameworks&lt;/h2&gt;

&lt;p&gt;I started to build my own framework when I was re-developing a project originally written in C#, I wanted something which was minimal and would cover 90% of my use cases, something which worked with my rather opinionated method of development and testing which is Google’s &lt;strong&gt;Go&lt;/strong&gt; as my language, &lt;strong&gt;Cucumber&lt;/strong&gt; and &lt;strong&gt;Ruby&lt;/strong&gt; for my functional test suite, &lt;strong&gt;Docker&lt;/strong&gt; stuff for my platform.&lt;/p&gt;

&lt;p&gt;When I first started to build microservices in Go I found that I would repeat the same scaffolding steps time and time again.  I would copy some boiler plate code for my functional tests and also for my build scripts.  It all became a little unmanageable by the time I had finished the second service, I had also learned a lot.  Thats when I first built &lt;a href=&quot;https://github.com/nicholasjackson/go-microservice-template&quot;&gt;go-microservice-template&lt;/a&gt; this worked really well for a while but I found that whilst it was fine to add the new learnings to the template it was a total pain to update existing services.&lt;/p&gt;

&lt;p&gt;Time for split, go-microservice-template was put out to pasture and the build and test framework was split out into a separate Rubygem called &lt;a href=&quot;http://nicholasjackson.github.io/minke/&quot;&gt;Minke&lt;/a&gt;.  With Minke I implemented the concept of Generators which would support scaffolding and building applications in multiple languages not just Go.  So far this has worked well, localising my build and test code into a gem has recently proven useful when I switched from my own Jenkins server to &lt;a href=&quot;https://circleci.com/&quot;&gt;CircleCI&lt;/a&gt; and found myself unable to use the &lt;code class=&quot;highlighter-rouge&quot;&gt;Docker exec&lt;/code&gt; command.  Being able to update a central gem saved hours and hours of copy and pasting.&lt;/p&gt;

&lt;h1 id=&quot;go-microservice-generator-for-minke&quot;&gt;Go Microservice Generator for Minke&lt;/h1&gt;

&lt;h2 id=&quot;installing-and-scaffolding-a-microservice&quot;&gt;Installing and scaffolding a microservice&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/images/posts/0_microservice/go_template.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Assuming your GOPATH is set correctly to get a copy of the template on your local computer and you have Ruby 2.x you need two gems installed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://rubygems.org/gems/minke&quot;&gt;Minke&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://rubygems.org/gems/minke-generator-go&quot;&gt;Minke Generator Go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install minke
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;gem install minke-generator-go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will install the two gems into your gem cache, to generate your service you simply execute following command (obviously changing the paths unless your github user is nicholasjackson in which case you will be me).&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ minke -g minke-generator-go -o $GOPATH/src/github.com/nicholasjackson/hello -n github.com/nicholasjackson -a hello
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The options for the above command are:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;text-align: left&quot;&gt;flag&lt;/th&gt;
      &lt;th&gt; &lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;-g&lt;/td&gt;
      &lt;td&gt;generator template to use&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;-o&lt;/td&gt;
      &lt;td&gt;output folder for generated code&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;-n&lt;/td&gt;
      &lt;td&gt;namespace for application&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;text-align: left&quot;&gt;-a&lt;/td&gt;
      &lt;td&gt;application name&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;The application will then scaffold the service for you and place the contents at:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$GOPATH&lt;/span&gt;/src/[your_namespace]/[service_name]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The service should be ready to build and deploy, complete with a couple of example endpoints, unit and functional tests.&lt;/p&gt;

&lt;h2 id=&quot;sprint-0&quot;&gt;Sprint 0&lt;/h2&gt;

&lt;p&gt;Scaffold the service and get it deploying to production.  If I had pound for every time a project has been delayed due to the complexities (software and people) of getting a service deployed to production I would currently be surfing and not writing this post.  I designed the template to be running and testable straight out of the box so that the next task can be to get it running in the continuous delivery pipeline.&lt;/p&gt;

&lt;p&gt;I recommend that this is not only set up for Dev and Test environments but you build the pipeline into production.  You do not need to expose the service but I certainly recommend deploying to production every time you commit to master as a matter of good practice.&lt;/p&gt;

&lt;h2 id=&quot;a-closer-look-at-the-scaffolded-service&quot;&gt;A closer look at the scaffolded service?&lt;/h2&gt;
&lt;p&gt;As I mentioned earlier I am a fan of the Bauhaus approach to my scaffolding; clean lines and minimalist.  There are however a few key things that I find I can not do without in every service.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;strong&gt;Dependency Injection&lt;/strong&gt; - My current favorite is the Facebook inject package &lt;a href=&quot;http://github.com/facebookgo/inject&quot;&gt;github.com/facebookgo/inject&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Routing&lt;/strong&gt; - Tried and tested it has to be Gorilla all the way &lt;a href=&quot;http://github.com/gorilla&quot;&gt;github.com/gorilla&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Request Validation&lt;/strong&gt; - As my friend Yan Ettles would say “Input Validation, Input Validation, Input Validation”, security is essential and this is a good place to start &lt;a href=&quot;http://github.com/asaskevich/govalidator&quot;&gt;github.com/asaskevich/govalidator&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Logging&lt;/strong&gt; - Metrics are incredibly important, personally I like to use &lt;a href=&quot;https://github.com/etsy/statsd&quot;&gt;StatsD&lt;/a&gt; for simple metrics you can store these in a service like &lt;a href=&quot;https://www.datadoghq.com/blog/statsd/&quot;&gt;Datadog&lt;/a&gt; or if you need to host your own you can use &lt;a href=&quot;http://graphite.wikidot.com&quot;&gt;Graphite&lt;/a&gt; and &lt;a href=&quot;http://graphite.readthedocs.io/en/latest/carbon-daemons.html&quot;&gt;Carbon&lt;/a&gt;. For more detailed logs &lt;a href=&quot;http://linux.die.net/man/8/syslogd&quot;&gt;Syslogd&lt;/a&gt; will do the trick you can export your logs to either something like &lt;a href=&quot;https://www.loggly.com&quot;&gt;Loggly&lt;/a&gt; or your own ELK (Elasticsearch, Logstash, Kibana) stack.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&quot;dependency-injection&quot;&gt;Dependency Injection&lt;/h3&gt;
&lt;p&gt;The Facebook framework is excellent allowing you to inject:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Shared instances of objects.&lt;/li&gt;
  &lt;li&gt;Named instances of objects, useful when the framework can not infer from the type such as when using an interface.&lt;/li&gt;
  &lt;li&gt;Private objects which are unique to each injected class.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This does not feel very Go like and there are a lot of question on why you need to use dependency injection in Go when you can just have a shared package which stores references.  For me it is largely about the ugliness and brittleness of the code when using a shared package but also Facebook inject has some nice features like it will traverse a tree when creating an object, automatically creating and injecting sub dependencies.  Take a look at handlers/health.go and handlers/health_test.go for an example of use, the initial graph creation takes place in the main startup method.&lt;/p&gt;

&lt;p&gt;There is some weird code in the health handler which I must warn you about:&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statusMessage&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SetStatusMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statusMessage&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponse&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponse&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatusMessage&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;statusMessage&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hr&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthDependenciesContainer&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// if not specified will create singleton&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SingletonBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`inject:&quot;&quot;`&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// statsD interface must use a name type as injection cannot infer ducktypes&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Stats&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatsD&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`inject:&quot;statsd&quot;`&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;c&quot;&gt;// if not specified in the graph will automatically create private instance&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PrivateBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthResponseBuilder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`inject:&quot;private&quot;`&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I generally would not write code like this for such a simple purpose it is purely as an example to myself as to what is possible with Facebook inject.&lt;/p&gt;

&lt;h3 id=&quot;routing&quot;&gt;Routing&lt;/h3&gt;
&lt;p&gt;When it comes to routing I have used the &lt;a href=&quot;http://www.gorillatoolkit.org/pkg/&quot;&gt;Gorilla Toolkit&lt;/a&gt; since my first go application, it is fast and does everything I need.  The handlers package deals with the routing and setting up a new handler with Gorilla is a breeze.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/v1/health&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HealthHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;POST&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/v1/echo&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;requestValidationHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHO_HANDLER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reflect&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TypeOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}),&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;RouterDependencies&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;StatsD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HandlerFunc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EchoHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are using two different ways of registering a handler the simpler Get which takes a path and function and the more complex Add.  The more complex option is so we can add some middleware before our handler gets called, this is where we perform our validation and what I will get on to next.&lt;/p&gt;

&lt;h3 id=&quot;request-validation&quot;&gt;Request Validation&lt;/h3&gt;
&lt;p&gt;The go validator package &lt;a href=&quot;http://github.com/asaskevich/govalidator&quot;&gt;github.com/asaskevich/govalidator&lt;/a&gt; is awesome, it allows us to use struct annotation to define what valid is for our properties and then by simply calling a method on the validator package we get an array of error messages and an error object if the validation fails.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;`json:&quot;echo&quot; valid:&quot;stringlength(1|255),required&quot;`&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Valid String&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;govalidator&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ValidateStruct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When we wire up this code into middleware like in the &lt;strong&gt;requestValidationHandler&lt;/strong&gt; we have the ability to ensure our routing goes through the middleware before the handler, this means we can implement painless request validation for every handler.  govalidator has just about every possible scenario you could like to cover including some really nice things like validating a string as a url or net address all is explained in the package docs.&lt;/p&gt;

&lt;h3 id=&quot;logging&quot;&gt;Logging&lt;/h3&gt;
&lt;p&gt;You need logging and I recommend lots and lots of metrics out via StatsD or something similar.  There are various options from Gauges, Counters, Timing Summary Statistics, and Sets but whatever you use having the right data will not only help you debug and diagnose a problem but you can setup alerting in systems such as Datadog to wake you up in the middle of the night when something goes wrong, and believe me it will go wrong.  The simple implementation in the template is just using Increment (Counter) but it is easy to add other measures if required.  When you run the application &lt;a href=&quot;http://graphite.wikidot.com/&quot;&gt;Graphite&lt;/a&gt; is also spun up which is accessible at http://192.168.99.100:8080/ where 192.168.99.100 is the ip address of your docker machine.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/0_microservice/graphite.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I have also stated an opinion on a way to define the tags for the various metrics in const.go in the handlers package.  Ideally you do not want to only create a common format for metric tags in your microservice but treat it like a coding standard. Stick to the same format for every service, it will make dashboard creation a thousand times easier and you will not have to spend a week refactoring all the tags across 20 microservices because they were difficult to understand.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;handlers&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.get&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.post&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;CALLED&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.called&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SUCCESS&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.success&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;BAD_REQUEST&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.bad_request&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;INVALID_REQUEST&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.invalid_request&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;VALID_REQUEST&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;.valid_request&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;HEALTH_HANDLER&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;helloworld.health_handler&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ECHO_HANDLER&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;helloworld.echo_handler&quot;&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;testing&quot;&gt;Testing&lt;/h1&gt;
&lt;p&gt;Testing with go-microservice-template is broken into two groups:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Unit tests (Go)&lt;/li&gt;
  &lt;li&gt;Functional tests (Cucumber)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I follow an outside in methodology when writing code, this is my preference it works for me therefore my framework does this too.  I did say this was an opinionated framework didn’t I?&lt;br /&gt;
&lt;img src=&quot;/images/posts/0_microservice/outside-in-development.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;unit-tests&quot;&gt;Unit tests&lt;/h2&gt;
&lt;p&gt;The nice thing about Go is that you can test handlers independently from the HTTP server which allows you to tests the logic of your handler really quickly.  Combine this with the dependency injection framework to isolate dependencies or inject mocks, you have a really efficient and fast way to do test driven development.&lt;/p&gt;

&lt;p&gt;The below code is one of the tests, we are mocking the request and checking the response, since there is no HTTP server involved these tests are actually really fast to run.  This gives us the ability to write full coverage on our handlers as well as other logic, the only bit not covered is the wiring of the router and the start of the service but this will get coverage from the functional tests.&lt;/p&gt;

&lt;div class=&quot;language-go highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TestEchoHandlerCorrectlyEchosResponse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;testing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echoTestSetup&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseRecorder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;httptest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ResponseRecorder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseRecorder&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;httptest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NewRecorder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;request&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;EchoHandler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseRecorder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseRecorder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:=&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Unmarshal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;

  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;m&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;responseRecorder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Echo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;x&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;x&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;functional-tests&quot;&gt;Functional tests&lt;/h2&gt;
&lt;p&gt;All the functional tests are in the _build/features folder and are written in Gherkin.  Cucumber is my weapon of choice, Ruby and Rspec are just perfect for the job and there are quite a few cucumber plugins which have been developed meaning you need to write very few actual step implementations.  Following this method  you gain the ability to create some oh so essential integration tests and a really nice way to express the behavior of the service which defines the contract between you and the client.&lt;/p&gt;

&lt;div class=&quot;language-gherkin highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kn&quot;&gt;Scenario&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; Echo returns same data as posted
  &lt;span class=&quot;nf&quot;&gt;Given &lt;/span&gt;I send a POST request to &lt;span class=&quot;s&quot;&gt;&quot;/v1/echo&quot;&lt;/span&gt; with the following
    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;Hello&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;World&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;Then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;response&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;200&quot;&lt;/span&gt;
  &lt;span class=&quot;nf&quot;&gt;And &lt;/span&gt;the JSON response should have &lt;span class=&quot;s&quot;&gt;&quot;$..echo&quot;&lt;/span&gt; with the text &lt;span class=&quot;s&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;By using a gem such as &lt;a href=&quot;https://Rubygems.org/gems/cucumber-rest-api/versions/0.3&quot;&gt;cucumber-rest-api&lt;/a&gt; the above cucumber feature will execute without needing a single step file (NOTE: version 0.4 of this gem is broken).  That is not so difficult to maintain, all you cucumber haters complaining about your slow and brittle test suite already screaming NOOOO.  I’m going to make a statement, you won’t like it and it will most likely fill my comments with hate but here goes anyway.&lt;/p&gt;

&lt;h3 id=&quot;its-not-cucumber-its-you&quot;&gt;It’s not cucumber it’s you!&lt;/h3&gt;
&lt;p&gt;Test the behavior of your contract, a little integration and trust your unit tests to cover the rest, more often than not test coverage in functional tests is way too high. The other benefit of microservices are that your bloated test coverage will be distributed across multiple repos, instant test paralyzation.&lt;/p&gt;

&lt;h1 id=&quot;minke&quot;&gt;Minke&lt;/h1&gt;
&lt;p&gt;Minke is an opinionated build system for Docker based microservices like go-microservice-template it encapsulates all the horrible boilerplate build scripts and wraps them up so you only need to deal with config files like the extract below. I will not go to much into depth with minke it is worth reading the readme at &lt;a href=&quot;https://nicholasjackson.github.com/minke&quot;&gt;https://nicholasjackson.github.com/minke&lt;/a&gt; however we will look at the commands which build and test your microservice.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nn&quot;&gt;---&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;application_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;helloworld'&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;github.com/nicholasjackson'&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;generator_name&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;minke-generator-go'&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;docker_registry&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV['DOCKER_REGISTRY_URL'] %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV['DOCKER_REGISTRY_USER'] %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV['DOCKER_REGISTRY_PASS'] %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV['DOCKER_REGISTRY_EMAIL'] %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV['DOCKER_NAMESPACE'] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Inside the _build folder is a Gemfile with all the Ruby dependencies in it like Minke, before we can build our service we need to install them, you need a Ruby interpreter, personally I recommend RVM to manage the different versions of Ruby and all the dependencies.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Ensure Docker server is running and you have the docker environment variables set.&lt;/li&gt;
  &lt;li&gt;Install the gems with &lt;code class=&quot;highlighter-rouge&quot;&gt;bundle install&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Build the service &lt;code class=&quot;highlighter-rouge&quot;&gt;rake app:build_image&lt;/code&gt; this will get the go package dependencies, run the unit tests, build the application for linux then wrap everything nicely up into a Docker image.&lt;/li&gt;
  &lt;li&gt;Run the functional tests &lt;code class=&quot;highlighter-rouge&quot;&gt;rake app:cucumber&lt;/code&gt; to spin up our mock environment using Docker Compose and execute the Cucumber tests against it.  All things well you would see the following output from the terminal, if something did not work it will most likely be because you have not got your dependencies like Docker installed or set up correctly.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/images/posts/0_microservice/cucumber.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;consul&quot;&gt;Consul&lt;/h2&gt;
&lt;p&gt;To feed config to our service we will use consul and &lt;a href=&quot;https://github.com/hashicorp/consul-template&quot;&gt;consul template&lt;/a&gt;, the consul template can be found in _build/dockerfile/[servicename]/config.ctmpl. Consul template runs as a service in the container and checks for changes in &lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt; server.  It will write the value that corresponds to the key and restart the server when a change is detected.  The config itself is stored in a yaml file consul_keys.yml which Minke loads into consul on the start of the tests or when you run the application.  Below is a simple example of a Consul template for our service, Consul is written in Go and the templates are actually Go templates.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stats_d_server&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;{ {key &quot;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;app/stats_d_server&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;} }&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;docker-container&quot;&gt;Docker Container&lt;/h2&gt;
&lt;p&gt;Ah Docker, the thing pay rises are made from, I love Docker, in fact I loath to use anything else for packaging and running an application these days.  With the rise of services like Docker Cloud, Amazon Container Service and Google Container Service, long gone are the days of fighting with Chef and all things Unix which I have never fully understood.  Docker is also just about perfect, no essential if you are building a microservice architecture, the pain it causes will be an order of magnitude lower than not using it.&lt;/p&gt;

&lt;p&gt;Minke builds your code and wraps it up in a nice warm Docker blankie, check out the _build/dockerfile/[servicename]/ for more details but the dockerfile that go-microservice-template creates is based on Alpine linux which creates a nice small image, you can read more about that part of the process in another post here: &lt;a href=&quot;http://nicholasjackson.github.io/other/micro-docker-images-for-microservices/&quot;&gt;http://nicholasjackson.github.io/other/micro-docker-images-for-microservices/&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;docker-compose&quot;&gt;Docker Compose&lt;/h2&gt;
&lt;p&gt;When you run or test your application Minke uses Docker Compose, if you examine the compose file in the build folder, you will see entries for consul and our StatsD server.  As my service grows in complexity so does this file, in order to control behavior from dependencies when I am testing my code I generally use mock servers like &lt;a href=&quot;https://github.com/nicholasjackson/mimic&quot;&gt;Mimic&lt;/a&gt;.  I try keep real dependencies like databases or queues to a minimum, as a rule of thumb on how micro is micro I would suggest that if you need to connect to more than one datastore your service might be two big.  All other connections should be to other services which can be mocked.&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;2'&lt;/span&gt;
&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;helloworld_test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;helloworld&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;::8001&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;CONSUL=consul:8500&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;consul:consul&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;statsd:statsd&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;consul&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;progrium/consul&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;::8500&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;hostname&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;node1&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-server&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-bootstrap&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-ui-dir&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/ui&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;statsd&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;hopsoft/graphite-statsd&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;::80&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;expose&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;8125/udp&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SERVICE_NAME=statsd&quot;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;registrator&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;gliderlabs/registrator:latest'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;links&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;consul:consul&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-internal&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;-tags=dev&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s&quot;&gt;consul://consul:8500'&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;/var/run/docker.sock:/tmp/docker.sock'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;cicd&quot;&gt;CI/CD&lt;/h1&gt;
&lt;p&gt;Sprint 0 get helloworld running under ci and deploying to an environment, I mentioned this earlier but I can not stress how much it will save your ass to keep your CI pipeline healthy, I have recently switched to CircleCI as they are capable of building both iOS and Android as well as my microservices.  To get a Go based microservice running on CircleCI took a little wrangling at first as whilst the auto-detection and build process is nice it does not allow for Minke to do its magic.  It is simple enough to configure to run the way we want as the below config shows.&lt;/p&gt;

&lt;p&gt;To get your service building all you need to do is change the paths in the dependencies section to point to your namespace and project name.  I have much love for CircleCI right now my builds take about 4 minutes for a service and most of that is setting up the environment, the UI is nice and clean and easy to use and the ability to SSH into the build host was absolutely essential when I was trying to figure out this config.&lt;/p&gt;

&lt;h2 id=&quot;circleci-config&quot;&gt;CircleCI Config&lt;/h2&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;machine&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;pre&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;curl -sSL https://s3.amazonaws.com/circle-downloads/install-circleci-docker.sh | bash -s -- 1.10.0&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo rm /usr/local/bin/docker-compose&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo curl -L https://github.com/docker/compose/releases/download/1.7.1/docker-compose-`uname -s`-`uname -m` &amp;gt; docker-compose&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;sudo mv docker-compose /usr/local/bin/&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;chmod +x /usr/local/bin/docker-compose&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;2.3.1&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;docker&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;GOPATH&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;/home/ubuntu/go&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;dependencies&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cd _build &amp;amp;&amp;amp; bundle &amp;amp;&amp;amp; bundle update&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;mkdir -p /home/ubuntu/go/src/github.com/nicholasjackson&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cp -R /home/ubuntu/helloworld /home/ubuntu/go/src/github.com/nicholasjackson/&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;cd /home/ubuntu/go/src/github.com/nicholasjackson/helloworld/_build &amp;amp;&amp;amp; rake app:build_image &amp;amp;&amp;amp; rake app:cucumber&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Thats it we are done, 0 to microservice in 5 minutes, following the simple steps:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Scaffold a new service (go run generate.go)&lt;/li&gt;
  &lt;li&gt;Run the build script (rake app:build_image)&lt;/li&gt;
  &lt;li&gt;Run the tests (rake app:cucumber)&lt;/li&gt;
  &lt;li&gt;Create the circle.yml config&lt;/li&gt;
  &lt;li&gt;Tell CircleCI to watch your project&lt;/li&gt;
  &lt;li&gt;Push the code to your repo&lt;/li&gt;
  &lt;li&gt;Boil the kettle and sit back and wait for the build to go green&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For me this will always be work in progress and as I learn more I will update both Minke and minke-generator-go but for now this pattern is really working for me. If you have any comments please feel free to ping me a message, find a bug, always happy for contributions.&lt;/p&gt;

&lt;p&gt;In the next post I am going to write more in-depth about service discovery and some software patterns for managing disconnected services.&lt;/p&gt;

&lt;h2 id=&quot;source-code&quot;&gt;Source Code&lt;/h2&gt;
&lt;p&gt;If you need it please check out the example project at &lt;a href=&quot;https://github.com/nicholasjackson/helloworld&quot;&gt;https://github.com/nicholasjackson/helloworld&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;dependencies&quot;&gt;Dependencies&lt;/h1&gt;
&lt;p&gt;Stuff to install or nothing will work and you will swear at me.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Ruby &lt;a href=&quot;https://rvm.io/&quot;&gt;https://rvm.io/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Go &lt;a href=&quot;https://golang.org/&quot;&gt;https://golang.org/&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Docker Toolbox including Docker Compose &lt;a href=&quot;https://www.docker.com/products/docker-toolbox&quot;&gt;https://www.docker.com/products/docker-toolbox&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;CircleCI &lt;a href=&quot;https://circleci.com/&quot;&gt;https://circleci.com/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Fri, 26 Feb 2016 00:00:00 +0000</pubDate>
        <link>https://nicholasjackson.io/2016/02/26/building-and-testing-microservices-part1/</link>
        <guid isPermaLink="true">https://nicholasjackson.io/2016/02/26/building-and-testing-microservices-part1/</guid>
        
        <category>microservices</category>
        
        <category>go</category>
        
        <category>minke</category>
        
        
      </item>
    
  </channel>
</rss>
