<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mario Carrion</title>
    <description>The latest articles on DEV Community by Mario Carrion (@mariocarrion).</description>
    <link>https://dev.to/mariocarrion</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F448247%2F2b799227-ac3f-424f-856d-522e2d9a53f7.png</url>
      <title>DEV Community: Mario Carrion</title>
      <link>https://dev.to/mariocarrion</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mariocarrion"/>
    <language>en</language>
    <item>
      <title>Microservices in Go: Events and Background jobs using Kafka</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Fri, 03 Sep 2021 00:36:03 +0000</pubDate>
      <link>https://dev.to/mariocarrion/microservices-in-go-events-and-background-jobs-using-kafka-3pe1</link>
      <guid>https://dev.to/mariocarrion/microservices-in-go-events-and-background-jobs-using-kafka-3pe1</guid>
      <description>&lt;p&gt;Post originally published at &lt;a href="https://mariocarrion.com/2021/06/03/golang-microservices-events-streaming-kafka.html" rel="noopener noreferrer"&gt;mariocarrion.com&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Kafka?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://kafka.apache.org/" rel="noopener noreferrer"&gt;Kafka&lt;/a&gt; is an &lt;em&gt;event streaming platform&lt;/em&gt;, it allows us to &lt;strong&gt;publish&lt;/strong&gt;, &lt;strong&gt;subscribe&lt;/strong&gt;, &lt;strong&gt;store&lt;/strong&gt; and &lt;strong&gt;process&lt;/strong&gt; events. An &lt;strong&gt;Event&lt;/strong&gt; indicates something that happened, if we use our &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example" rel="noopener noreferrer"&gt;To Do Microservice&lt;/a&gt; as example, we could define events to indicate a &lt;code&gt;TaskCreated&lt;/code&gt; or &lt;code&gt;TaskUpdated&lt;/code&gt; when a Task is created or when a Task is updated, respectively.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does Kafka work?
&lt;/h2&gt;

&lt;p&gt;In Kafka there's a concept called &lt;em&gt;Topic&lt;/em&gt;, &lt;em&gt;Topics&lt;/em&gt; store events published by a &lt;em&gt;Publisher&lt;/em&gt;; those &lt;em&gt;Topics&lt;/em&gt; can be named for to differentiate between them and they can be &lt;em&gt;Partitioned&lt;/em&gt;, what this means is that they could be separated into multiple Kafka brokers, or instances in charge of storing the topics, defining various partitions allows scaling Kafka to allow multiple publishers and consumers to write and read data.&lt;/p&gt;

&lt;p&gt;When an event is published to a &lt;em&gt;Topic&lt;/em&gt; it will be stored in order it was received, this allows the &lt;em&gt;Consumers&lt;/em&gt; to read those events in the same order they were published:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F1.png%3Fsrc%3Ddevto2" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F1.png%3Fsrc%3Ddevto2" alt="Kafka Topics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Consumers&lt;/em&gt; use &lt;em&gt;Group IDs&lt;/em&gt; to identify themselves when reading events that way multiple processes can consume the same topic in a way the events are still consumed in order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F2.png%3Fsrc%3Ddevto" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F2.png%3Fsrc%3Ddevto" alt="Kafka Topics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of those &lt;em&gt;Group IDs&lt;/em&gt;, multiple processes can read the same data at a different pace of speed without affecting other consumers:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F3.png%3Fsrc%3Ddevto" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F06%2F03%2F3.png%3Fsrc%3Ddevto" alt="Kafka Topics"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publisher implementation using a Repository
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/8f7d667a2136c66ad2f893c7802edf46cafd6f35" rel="noopener noreferrer"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For communicating with Kafka we are going to use the official package &lt;a href="https://github.com/confluentinc/confluent-kafka-go" rel="noopener noreferrer"&gt;&lt;code&gt;confluentinc/confluent-kafka-go&lt;/code&gt;&lt;/a&gt; and similar to other &lt;a href="https://mariocarrion.com/2021/04/04/golang-microservices-repository-pattern.html" rel="noopener noreferrer"&gt;Repositories&lt;/a&gt; we implemented previously a new package will be defined called &lt;code&gt;kafka&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This package will implement the corresponding &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/8f7d667a2136c66ad2f893c7802edf46cafd6f35/internal/kafka/task.go" rel="noopener noreferrer"&gt;&lt;code&gt;Task&lt;/code&gt;&lt;/a&gt; in charge of publishing the events that represent the actions executed when Tasks change to indicate creation, deletion and updates.&lt;/p&gt;

&lt;p&gt;The code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Deleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Updated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those exported methods use an unexported method called &lt;code&gt;publish&lt;/code&gt; that interacts directly with the Kafka Producer, the event to be sent will be encoded using &lt;code&gt;encoding/json&lt;/code&gt;, the idea is to define a JSON payload that then our Consumers can use for determine what event to use, more in the section below covering &lt;em&gt;Consumers&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spanName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routingKey&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;

    &lt;span class="n"&gt;evt&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;msgType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;producer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Produce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;TopicPartition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TopicPartition&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Topic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;topicName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Partition&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PartitionAny&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To connect this Kafka repository with the PostgreSQL repository we will update each method in &lt;code&gt;service.Task&lt;/code&gt; to call the corresponding publish-related method, &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/8f7d667a2136c66ad2f893c7802edf46cafd6f35/internal/service/task.go#L62-L76" rel="noopener noreferrer"&gt;for example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// XXX: Transactions will be revisited in future episodes.&lt;/span&gt;
    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msgBroker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: Ignoring errors on purpose&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refer to the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/8f7d667a2136c66ad2f893c7802edf46cafd6f35/internal/service/task.go" rel="noopener noreferrer"&gt;original code&lt;/a&gt; to see how the other methods were updated to do something similar.&lt;/p&gt;

&lt;p&gt;For consuming the events we will define a new program that will be using the same topic to read the data we published, and then it will update the Elasticsearch values using that repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consumer implementation
&lt;/h2&gt;

&lt;p&gt;Like I mentioned above the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/8f7d667a2136c66ad2f893c7802edf46cafd6f35/cmd/elasticsearch-indexer-kafka/main.go" rel="noopener noreferrer"&gt;new program&lt;/a&gt; will consume the Kafka events and depending on the event type it will call the corresponding &lt;a href="https://mariocarrion.com/2021/05/24/golang-microservices-searching-with-elasticsearch.html" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; method to reindex the values; this program also supports &lt;a href="https://mariocarrion.com/2021/05/21/golang-microservices-graceful-shutdown.html" rel="noopener noreferrer"&gt;Graceful shutdown&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The program uses the &lt;a href="https://pkg.go.dev/github.com/confluentinc/confluent-kafka-go/kafka#Consumer" rel="noopener noreferrer"&gt;&lt;code&gt;Consumer&lt;/code&gt;&lt;/a&gt; to poll the values that represent the events &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/8f7d667a2136c66ad2f893c7802edf46cafd6f35/cmd/elasticsearch-indexer-kafka/main.go#L142-L190" rel="noopener noreferrer"&gt;to read&lt;/a&gt;, the simplified code looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Consumer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Poll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;150&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;kafka&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;evt&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="n"&gt;internaldomain&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;evt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;evt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.created"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// call Elasticsearch to index record&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.deleted"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// call Elasticsearch to delete record&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When building your final program consider implementing a &lt;em&gt;Server&lt;/em&gt;-like type, with the goal of separating the different received events into their corresponding types, that way your &lt;code&gt;switch&lt;/code&gt; could be replaced with a map of functions pointing to the &lt;em&gt;"handlers"&lt;/em&gt; of each type being consumed.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;Kafka&lt;/em&gt; is a powerful platform for dealing with events, it could be used as a message broker to distribute information across multiple services but it also supports storing and replaying events as well as analysis of those events they are received.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to do something similar in RabbitMQ and Redis, I recommend reading the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariocarrion.com/2021/05/28/golang-microservices-events-background-jobs-rabbitmq.html" rel="noopener noreferrer"&gt;Microservices in Go: Events and Background jobs using RabbitMQ&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariocarrion.com/2021/06/10/golang-microservices-pub-sub-redis.html" rel="noopener noreferrer"&gt;Microservices in Go: Using Pub/Sub with Redis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;This post includes icons made by &lt;a href="https://www.flaticon.com/authors/itim2101" rel="noopener noreferrer"&gt;itim2101&lt;/a&gt; from &lt;a href="https://www.flaticon.com/" rel="noopener noreferrer"&gt;Flaticon&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>kafka</category>
    </item>
    <item>
      <title>Learning Go: Context package</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Fri, 27 Aug 2021 02:38:48 +0000</pubDate>
      <link>https://dev.to/mariocarrion/learning-go-context-package-oi3</link>
      <guid>https://dev.to/mariocarrion/learning-go-context-package-oi3</guid>
      <description>&lt;p&gt;Back in August 2016 &lt;a href="https://blog.golang.org/go1.7" rel="noopener noreferrer"&gt;Go 1.7 was released&lt;/a&gt;, it included among other things a new package called &lt;a href="https://pkg.go.dev/context" rel="noopener noreferrer"&gt;&lt;code&gt;context&lt;/code&gt;&lt;/a&gt;. This package was originally implemented in &lt;a href="https://pkg.go.dev/golang.org/x/net/context" rel="noopener noreferrer"&gt;&lt;code&gt;golang.org/x/net/context&lt;/code&gt;&lt;/a&gt; but it was copied over to the standard library during this release.&lt;/p&gt;

&lt;p&gt;This change made other standard library packages, like &lt;code&gt;net&lt;/code&gt;, &lt;code&gt;net/http&lt;/code&gt; and &lt;code&gt;database/sql&lt;/code&gt;, to be updated to add support for the &lt;code&gt;context&lt;/code&gt; package &lt;strong&gt;but&lt;/strong&gt; without breaking existing APIs. That's why we see functions with similar name and arguments but with an extra &lt;code&gt;context&lt;/code&gt; argument added as the first one, like &lt;code&gt;database/sql.*DB&lt;/code&gt; 's &lt;code&gt;Ping&lt;/code&gt; method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;PingContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This decision was made because of the &lt;a href="https://golang.org/doc/go1compat" rel="noopener noreferrer"&gt;version one compatibility&lt;/a&gt; promise, however behind the scenes most of those methods use &lt;code&gt;context&lt;/code&gt; but &lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.16.6:src/database/sql/sql.go;l=816" rel="noopener noreferrer"&gt;with default values&lt;/a&gt;, usually &lt;code&gt;context.Background()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Ping&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PingContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important thing to notice about those new methods is the fact that they defined a &lt;em&gt;de-facto&lt;/em&gt; convention where if we need to use &lt;code&gt;context.Context&lt;/code&gt; in our functions then it should be the first argument called &lt;code&gt;ctx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let's dive into the &lt;code&gt;context&lt;/code&gt; package.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is in the &lt;code&gt;context&lt;/code&gt; package?
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;context&lt;/code&gt; package defines a type called &lt;code&gt;Context&lt;/code&gt; that is used for &lt;strong&gt;deadlines&lt;/strong&gt;, &lt;strong&gt;cancellation signals&lt;/strong&gt; as well as a way to use &lt;strong&gt;request-scoped values&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;context.Context&lt;/code&gt; is an interface type that defines four functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Deadline&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on how we plan to use &lt;code&gt;context.Context&lt;/code&gt; we may or may not use all the methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Deadline()&lt;/code&gt;: returns the time when the context should end, if no deadline is set then the returned bool value is &lt;code&gt;false&lt;/code&gt;. This function is useful in cases where a &lt;code&gt;context&lt;/code&gt; is received and we want to calculate if there's enough time to complete the work to be done.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Done()&lt;/code&gt;: returns a channel that is closed when the context ends, the way this channel is closed depends on how the &lt;code&gt;context.Context&lt;/code&gt; was initialized, please refer to the docs for &lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.16.6:src/context/context.go;l=68-77" rel="noopener noreferrer"&gt;concrete details&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Err()&lt;/code&gt;: &lt;em&gt;if&lt;/em&gt; there was an error then it returns a non-nil error when the returned channel in &lt;code&gt;Done()&lt;/code&gt; was closed, either &lt;code&gt;context.DeadlineExceeded&lt;/code&gt; or &lt;code&gt;context.Canceled&lt;/code&gt;, otherwise &lt;code&gt;nil&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Value(key interface{})&lt;/code&gt;: it's used to get a request-scoped value stored in the &lt;em&gt;context&lt;/em&gt;, used in conjunction with &lt;a href="https://pkg.go.dev/context#WithValue" rel="noopener noreferrer"&gt;&lt;code&gt;context.WithValue&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's most likely you're already using &lt;code&gt;context&lt;/code&gt; in one way or another, for example if you're using &lt;code&gt;database/sql&lt;/code&gt; or &lt;code&gt;net/http&lt;/code&gt;; some projects rely heavily on &lt;code&gt;context&lt;/code&gt; to achieve their goal, for example &lt;a href="https://mariocarrion.com/2021/05/13/golang-microservices-opentelemetry.html" rel="noopener noreferrer"&gt;OpenTelemetry&lt;/a&gt; uses it intensively for instrumentation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/videos/tree/563b41660420a5e77d25157f1d4798f343d12d22/2021/05/07" rel="noopener noreferrer"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deadlines
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Deadlines&lt;/strong&gt; define a way to indicate something has been completed using time, there are two ways to do that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Fdeadlines.png%3Fsrc%3Ddevto" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Fdeadlines.png%3Fsrc%3Ddevto" alt="Deadlines"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/context#WithDeadline" rel="noopener noreferrer"&gt;&lt;code&gt;context.WithDeadline&lt;/code&gt;&lt;/a&gt;: uses a concrete &lt;code&gt;time.Time&lt;/code&gt; to indicate when the &lt;em&gt;context&lt;/em&gt; should finish, and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/context#WithTimeout" rel="noopener noreferrer"&gt;&lt;code&gt;context.WithTimeout&lt;/code&gt;&lt;/a&gt;: uses a relative &lt;code&gt;time.Duration&lt;/code&gt; to indicate when the &lt;em&gt;context&lt;/em&gt; should finish.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you refer to the &lt;a href="https://cs.opensource.google/go/go/+/refs/tags/go1.16.6:src/context/context.go;l=502" rel="noopener noreferrer"&gt;source code&lt;/a&gt; you will notice that &lt;code&gt;context.WithTimeout&lt;/code&gt; uses &lt;code&gt;context.WithDeadline&lt;/code&gt; behind the scenes but adding the timeout to the current time to indicate the deadline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt; &lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timeout&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancelFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;WithDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both functions return a new &lt;code&gt;context.Context&lt;/code&gt; as well as a &lt;code&gt;context.CancelFunc&lt;/code&gt; function; this new &lt;code&gt;context.Context&lt;/code&gt; is a copy of the parent one with deadline details attached to it and it's meant to be used as the argument for any subsequent calls that are supposed to be using a deadline.&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;context.CancelFunc&lt;/code&gt; should be called (usually via a &lt;code&gt;defer&lt;/code&gt;) when the corresponding block of code using the new &lt;code&gt;context.Context&lt;/code&gt; is completed, this is to propagate the cancellation to other functions using the &lt;code&gt;context&lt;/code&gt; in case the deadline was reached.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://github.com/MarioCarrion/videos/blob/563b41660420a5e77d25157f1d4798f343d12d22/2021/05/07/main_deadline.go" rel="noopener noreferrer"&gt;example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;After&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"overslept"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c"&gt;// prints "context deadline exceeded"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above will always print &lt;code&gt;context deadline exceeded&lt;/code&gt; because the value we indicated in the call &lt;code&gt;context.WithTimeout&lt;/code&gt; is &lt;em&gt;1 millisecond&lt;/em&gt;, if we modify that value to be something higher than &lt;em&gt;1 second&lt;/em&gt; then it will print out &lt;code&gt;overslept&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is because the &lt;code&gt;select&lt;/code&gt; is expecting for one of two channels to receive a message, either the one returned by &lt;code&gt;time&lt;/code&gt; (via &lt;code&gt;time.After()&lt;/code&gt;) or the one indicated in &lt;code&gt;context&lt;/code&gt; (via &lt;code&gt;ctx.Done()&lt;/code&gt;).&lt;/p&gt;

&lt;h3&gt;
  
  
  Cancellation signals
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Cancellation signals&lt;/strong&gt; define a way to indicate something has been completed by explicitly calling a &lt;code&gt;CancelFunc&lt;/code&gt; function, there is one way to do it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Fcancellation.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Fcancellation.png" alt="Cancellation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/context#WithCancel" rel="noopener noreferrer"&gt;&lt;code&gt;context.WithCancel&lt;/code&gt;&lt;/a&gt;: it returns a copy of the &lt;em&gt;context&lt;/em&gt; and a &lt;code&gt;CancelFunc&lt;/code&gt; to indicate when to cancel some work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Similar to the &lt;em&gt;Deadlines&lt;/em&gt;, for &lt;strong&gt;Cancellation signals&lt;/strong&gt; a &lt;em&gt;context.Context&lt;/em&gt; is returned as well as a &lt;code&gt;CancelFunc&lt;/code&gt;; this function should be explicitly called to indicate when a returned &lt;em&gt;context&lt;/em&gt; is canceled to propagate to other functions using the same &lt;em&gt;context&lt;/em&gt; the work should stop.&lt;/p&gt;

&lt;p&gt;The difference between &lt;code&gt;context.WithCancel&lt;/code&gt; and &lt;code&gt;context.WithDeadline&lt;/code&gt;/&lt;code&gt;context.WithTimeout&lt;/code&gt; is the explicitness, so instead of defining a &lt;em&gt;timeout&lt;/em&gt; the &lt;code&gt;CancelFunc&lt;/code&gt; should be called explicitly. In all three cases we always need to call the returned &lt;code&gt;CancelFunc&lt;/code&gt; to properly propagate the cancellation details to other functions using the same context.&lt;/p&gt;

&lt;p&gt;The function &lt;code&gt;context.CancelFunc&lt;/code&gt; should be called (usually via a &lt;code&gt;defer&lt;/code&gt;) when the corresponding block of code using the new &lt;code&gt;context.Context&lt;/code&gt; is completed, this is to propagate the cancellation to other functions using the &lt;code&gt;context&lt;/code&gt; in case the deadline was reached.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://github.com/MarioCarrion/videos/blob/563b41660420a5e77d25157f1d4798f343d12d22/2021/05/07/main_cancel.go" rel="noopener noreferrer"&gt;example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;

&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="c"&gt;// 2. "ctx" is cancelled, we close "ch"&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exiting"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="c"&gt;// returning not to leak the goroutine&lt;/span&gt;
        &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Millisecond&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"goodbye"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// 1. cancels "ctx"&lt;/span&gt;
&lt;span class="p"&gt;}()&lt;/span&gt;

&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"waiting to cancel..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="c"&gt;// 3. "ch" is closed, we exit&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bye"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above is a bit more elaborated than the one used for &lt;em&gt;Deadlines&lt;/em&gt;, the key part is the explicit &lt;code&gt;cancel()&lt;/code&gt; call in the goroutine; that &lt;code&gt;cancel()&lt;/code&gt; call is what in the end stops the &lt;code&gt;run&lt;/code&gt; function that receives the &lt;em&gt;cancelable context&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Request-scoped values
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Request-scoped values&lt;/strong&gt; define a way to set and get values that apply to concrete instances of &lt;em&gt;context.Context&lt;/em&gt;, they are meant to be used &lt;strong&gt;only&lt;/strong&gt; during a user request, for example during an HTTP request to pass down information to the subsequent internal calls, there is one way to do it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Frequest-scoped.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F31%2Frequest-scoped.png" alt="Request-scoped values"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/context#WithValue" rel="noopener noreferrer"&gt;&lt;code&gt;context.WithValue&lt;/code&gt;&lt;/a&gt;: it returns a copy of the &lt;em&gt;context&lt;/em&gt; that happens to include the value set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For &lt;a href="https://github.com/MarioCarrion/videos/blob/563b41660420a5e77d25157f1d4798f343d12d22/2021/05/07/main_value.go" rel="noopener noreferrer"&gt;example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer hi"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;//-&lt;/span&gt;

&lt;span class="n"&gt;bearer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;bearer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalln&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"not a string"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"value:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code above uses both &lt;code&gt;context.WithValue&lt;/code&gt; and &lt;code&gt;context.Context.Value&lt;/code&gt;; &lt;code&gt;context.WithValue&lt;/code&gt; returns a copy of the parent &lt;em&gt;context&lt;/em&gt; with the associated value and key, then we can use that returned &lt;em&gt;context&lt;/em&gt; and call its method &lt;code&gt;Value&lt;/code&gt; to get the previously assigned value.&lt;/p&gt;

&lt;p&gt;The complexity of &lt;code&gt;context.WithValue&lt;/code&gt; is not about the implementation or usage but rather &lt;em&gt;when&lt;/em&gt; to make those calls, recall the point of using this function is &lt;strong&gt;only&lt;/strong&gt; for request-scoped values not things meant to live all the time during the execution of the program.&lt;/p&gt;

&lt;p&gt;Some common examples include defining a value for JSON Web Tokens or extra headers, in both cases the values are meant to be passed around multiple requests to augment the subsequent requests.&lt;/p&gt;

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

&lt;p&gt;Understanding how to use &lt;code&gt;context.Context&lt;/code&gt; is important when dealing with instructions that require cancellation, for example HTTP requests, database commands or remote produce calls; not only because we need to define a sane value to indicate when to stop a running request to avoid waiting forever but also to identify when a remote call was canceled to properly react to that event.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;context.Context&lt;/code&gt; provides a simpler way to deal with multiple goroutines to coordinate their work, to identify timeouts and to determine when those happen. Because instrumentation is an important part of any distributed system, knowing how those values are sent and defined between different calls is useful to understand the flow of our program.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to expand more about &lt;code&gt;context.Context&lt;/code&gt;, I recommend reading the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariocarrion.com/2020/08/19/go-implementing-complex-pipelines-part-4.html" rel="noopener noreferrer"&gt;Complex Pipelines in Go (Part 4): Sane Coordination and Cancellation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.golang.org/context-and-structs" rel="noopener noreferrer"&gt;The Go Blog: Contexts and structs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.golang.org/context" rel="noopener noreferrer"&gt;The Go Blog: Go Concurrency Patterns: Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building Microservices in Go: Events and Background jobs using RabbitMQ</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Fri, 20 Aug 2021 05:05:37 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-events-and-background-jobs-using-rabbitmq-2gpf</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-events-and-background-jobs-using-rabbitmq-2gpf</guid>
      <description>&lt;p&gt;Originally published at &lt;a href="https://mariocarrion.com/2021/05/28/golang-microservices-events-background-jobs-rabbitmq.html" rel="noopener noreferrer"&gt;mariocarrion.com&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is RabbitMQ?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.rabbitmq.com/" rel="noopener noreferrer"&gt;RabbitMQ&lt;/a&gt; is a message-queueing software also known as a message broker or queue manager. It supports protocols such as &lt;a href="https://www.amqp.org/about/what" rel="noopener noreferrer"&gt;AMQP&lt;/a&gt;, &lt;a href="https://mqtt.org/" rel="noopener noreferrer"&gt;MQTT&lt;/a&gt; and &lt;a href="https://stomp.github.io/" rel="noopener noreferrer"&gt;STOMP&lt;/a&gt;, to name a few. RabbitMQ could be used for long-running tasks, for example background jobs, and for communication between different services.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does RabbitMQ work?
&lt;/h2&gt;

&lt;p&gt;The easiest analogy to describe RabbitMQ is that of a Post Office and the required steps involved, from beginning to end, to deliver a mail to the final destination. In real life those steps consist of dropping off the mail into a mailbox, then some processing behind the scenes to route that mail and finally a mail person brings that mail to the destination.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F28%2F1.png%3Fsrc%3Ddevto" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F28%2F1.png%3Fsrc%3Ddevto" alt="How does RabbitMQ Work? 1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RabbitMQ works as a queue where &lt;em&gt;Publishers&lt;/em&gt; can submit messages which then are eventually consumed by multiple &lt;em&gt;Consumers&lt;/em&gt;; however the interesting part about RabbitMQ is the intermediary mechanism that sits between those publishers and consumers. This intermediary is called &lt;em&gt;Exchange&lt;/em&gt;, this Exchange can be configured to define &lt;em&gt;Bindings&lt;/em&gt; to allow those messages to be routed into different &lt;em&gt;Queues&lt;/em&gt; which then the clients can listen to for consuming messages in different ways, to perhaps consume by a only concrete key or a wildcard.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F28%2F2.png%3Fsrc%3Ddevto" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmariocarrion.com%2Fimg%2F2021%2F05%2F28%2F2.png%3Fsrc%3Ddevto" alt="How does RabbitMQ Work? 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Publisher implementation using a Repository
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/b886f4346851c860728ec7924d8b3196139af11e" rel="noopener noreferrer"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To interact with RabbitMQ we will use the package &lt;a href="https://github.com/streadway/amqp" rel="noopener noreferrer"&gt;&lt;code&gt;streadway/amqp&lt;/code&gt;&lt;/a&gt; and similar to other data stores we will be defining a &lt;a href="https://mariocarrion.com/2021/04/04/golang-microservices-repository-pattern.html" rel="noopener noreferrer"&gt;Repository&lt;/a&gt; that will be interacting with the actual RabbitMQ publisher and will be called in the &lt;code&gt;service&lt;/code&gt; type.&lt;/p&gt;

&lt;p&gt;This repository type will be named &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/internal/rabbitmq/task.go" rel="noopener noreferrer"&gt;rabbitmq.Task&lt;/a&gt;, it will contain an unexported field referencing a RabbitMQ channel and the corresponding methods required for emitting three events &lt;code&gt;Created&lt;/code&gt;, &lt;code&gt;Deleted&lt;/code&gt; and &lt;code&gt;Updated&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.created"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Deleted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Updated&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those three methods will refer to an unexported method called &lt;code&gt;publish&lt;/code&gt;, which is used for publishing the data, this data is the result encoding the message using the &lt;code&gt;encoding/gob&lt;/code&gt; package, similar to the code used when we discussed &lt;a href="https://mariocarrion.com/2021/01/30/tips-building-microservices-in-go-golang-caching-memcached.html" rel="noopener noreferrer"&gt;Caching with Memcached&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;spanName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;routingKey&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gob&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"tasks"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c"&gt;// exchange&lt;/span&gt;
        &lt;span class="n"&gt;routingKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c"&gt;// routing key&lt;/span&gt;
        &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c"&gt;// mandatory&lt;/span&gt;
        &lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c"&gt;// immediate&lt;/span&gt;
        &lt;span class="n"&gt;amqp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Publishing&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;AppId&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;"tasks-rest-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ContentType&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/x-encoding-gob"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in the &lt;code&gt;service&lt;/code&gt; package the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/internal/service/task.go#L40-L46" rel="noopener noreferrer"&gt;&lt;code&gt;service.Task&lt;/code&gt;&lt;/a&gt; type is updated to receive an instance of that repository using an interface type, which then will be used it &lt;em&gt;after&lt;/em&gt; the persistent datastore call is done, something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;msgBroker&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Created&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please refer to the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/internal/service/task.go#L78-L92" rel="noopener noreferrer"&gt;&lt;code&gt;Delete&lt;/code&gt; call&lt;/a&gt; as well as the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/internal/service/task.go#L108-L128" rel="noopener noreferrer"&gt;&lt;code&gt;Update&lt;/code&gt; call&lt;/a&gt; for more details, in practice the code is similar to the one above.&lt;/p&gt;

&lt;p&gt;Now, let's take a look at the subscriber implementation. For this example we will implement a new running process in charge of consuming that data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Subscriber implementation
&lt;/h2&gt;

&lt;p&gt;This &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/cmd/elasticsearch-indexer/main.go" rel="noopener noreferrer"&gt;new process&lt;/a&gt; will consume those RabbitMQ events to properly index the Task records, changing the way we were using &lt;a href="https://mariocarrion.com/2021/05/24/golang-microservices-searching-with-elasticsearch.html" rel="noopener noreferrer"&gt;Elasticsearch&lt;/a&gt; originally, it will also support &lt;a href="https://mariocarrion.com/2021/05/21/golang-microservices-graceful-shutdown.html" rel="noopener noreferrer"&gt;Graceful shutdown&lt;/a&gt; like we previously covered.&lt;/p&gt;

&lt;p&gt;The code for listening, at the moment, is a slightly long &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/cmd/elasticsearch-indexer/main.go#L137-L226" rel="noopener noreferrer"&gt;method&lt;/a&gt;, the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/b886f4346851c860728ec7924d8b3196139af11e/cmd/elasticsearch-indexer/main.go#L176-L223" rel="noopener noreferrer"&gt;important part&lt;/a&gt; would be the actual Go channel returned by RabbitMQ, this code does something like the following to receive all events:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// XXX: Excluding some things for simplicity, please refer to the original code&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;msgs&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RoutingKey&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.updated"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.created"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// decode received Task event&lt;/span&gt;
        &lt;span class="c"&gt;// call Elasticsearch to index record&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="s"&gt;"tasks.event.deleted"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="c"&gt;// decode received Task event&lt;/span&gt;
        &lt;span class="c"&gt;// call Elasticsearch to delete record&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c"&gt;// acknowledege received event&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a real-life implementation you should consider implementing a &lt;em&gt;Server&lt;/em&gt; type able to handle different events, perhaps similar to the way &lt;code&gt;net/http.Server&lt;/code&gt; works and maybe define something similar to a Muxer to allow listening to multiple events with their corresponding encoding/decoding logic.&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;RabbitMQ&lt;/em&gt; is commonly known as a distributed queue but it can also be used as a message broker to communicate multiple services, is a powerful tool that thanks to the available configuration options could serve to deliver messages to multiple clients at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to do something similar in Kafka and Redis, I recommend reading the following links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mariocarrion.com/2021/06/03/golang-microservices-events-streaming-kafka.html" rel="noopener noreferrer"&gt;Microservices in Go: Events Streaming using Kafka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mariocarrion.com/2021/06/10/golang-microservices-pub-sub-redis.html" rel="noopener noreferrer"&gt;Microservices in Go: Using Pub/Sub with Redis&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;This post includes icons made by &lt;a href="https://www.flaticon.com/authors/itim2101" rel="noopener noreferrer"&gt;itim2101&lt;/a&gt; from &lt;a href="https://www.flaticon.com/" rel="noopener noreferrer"&gt;Flaticon&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>go</category>
      <category>rabbitmq</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Why you should use/learn Go as hiring manager/individual contributor.</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Fri, 13 Aug 2021 10:58:56 +0000</pubDate>
      <link>https://dev.to/mariocarrion/why-you-should-use-learn-go-as-hiring-manager-individual-contributor-l00</link>
      <guid>https://dev.to/mariocarrion/why-you-should-use-learn-go-as-hiring-manager-individual-contributor-l00</guid>
      <description>&lt;p&gt;When choosing a technology to build a software project the final decision will depend on the experience the team has and the risk they are allowed to take, using Go may not be the first choice because of the uncertainty the language can bring. This uncertainty can be measured by multiple &lt;em&gt;known unknowns&lt;/em&gt; like support (either commercial or community-based), availability of libraries and packages, documentation and examples, pool of available engineers or language complexity, to mention a few.&lt;/p&gt;

&lt;p&gt;Go is relatively a new programming language, it is &lt;a href="https://blog.golang.org/11years"&gt;11 years old (to date)&lt;/a&gt; and it is still evolving like any other language but in a slower pace compared to other ones, this is in my opinion because the promised &lt;a href="https://golang.org/doc/go1compat"&gt;version one compatibility&lt;/a&gt; at source level, this longevity is also another factor companies take into consideration during the decision making.&lt;/p&gt;

&lt;p&gt;In this post I will tackle different concerns related to whether using Go or not, those concerns will be from two point of views: &lt;strong&gt;Hiring Manager&lt;/strong&gt; and &lt;strong&gt;Individual Contributor&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hiring Manager
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Hiring Manager&lt;/strong&gt; is a broad term, for this post I define it as the &lt;em&gt;Person in charge of making the decisions of what Engineer to hire, and the expertise this person should have, for building a piece of software&lt;/em&gt;; this &lt;em&gt;Person&lt;/em&gt; is someone involved with the project that is part of that &lt;em&gt;piece of software&lt;/em&gt;, most of the times a &lt;em&gt;Lead Engineer&lt;/em&gt; that is trying to hire someone to join the project.&lt;/p&gt;

&lt;p&gt;This project could be new or current, for this specific post I'm assuming &lt;strong&gt;it's new&lt;/strong&gt; where Go is considered as one of technologies to use.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the cons?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Difficult to find talent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a valid concern, choosing a language that nobody knows or nobody is willing to learn delays the project and makes implementing this new piece of software harder than initially planned. Please continue reading there's more about this to explore regarding training and easiness to learn.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Training may be needed&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If people don't know the language then teaching them is going to be required, this is a con for sure but thanks to the language learning it may not take too much time or effort, however is something to consider and something that could delay the progress of the project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Salary or Compensation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If an Engineer with Go experience is found, it's most likely the compensation will be a bit higher because of the rarity of this combination, specially for Senior Engineers the compensation could be a big problem for companies not willing to make a good offer for this kind of experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the pros?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Easy to learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go is a &lt;em&gt;simple&lt;/em&gt;, yet &lt;em&gt;powerful&lt;/em&gt;, language. It does not define a lot of keywords or different ways to do things, sure there are few gotchas that could creep in when a novice engineer starts learning the language but in my opinion it is easy to learn and it tries its best to be as explicit as possible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Vendor-supported&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Part of choosing a technology, like programming language, consists of having options to use with other technologies, for example cloud providers like Google Cloud, Amazon Web Services and Azure provide SDKs in Go, the support may vary depending on the service but the option to use Go is there; popular datastores like &lt;a href="https://github.com/go-sql-driver/mysql"&gt;MySQL&lt;/a&gt;, &lt;a href="https://github.com/JackC/pgx"&gt;PostgreSQL&lt;/a&gt;, &lt;a href="https://github.com/go-redis/redis"&gt;Redis&lt;/a&gt;, &lt;a href="https://github.com/confluentinc/confluent-kafka-go"&gt;Kafka&lt;/a&gt; and &lt;a href="https://github.com/elastic/go-elasticsearch"&gt;Elasticsearch&lt;/a&gt; have packages available either created by the company providing commercial support or the community, so that's another thing to consider; not to mention the possibility to use any of the three most popular Operating Systems for development because it supports Microsoft Windows, Linux and MacOS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Individual Contributor
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Individual Contributor&lt;/strong&gt; is the person not in charge of hiring concerns, this person does get involved with the decisions being made regarding the technologies to use but as an &lt;em&gt;Individual Contributor&lt;/em&gt; this person is much more familiar with the internals of the codebase and the project being built. In the context of this post I also consider &lt;em&gt;Individual Contributor&lt;/em&gt; someone willing to spend time learning the Go language, considering the investments to make and the possible return of effort if the decision to use the language is made.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the cons?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Backend-friendly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're interested in using a programming language that can be used for both the Frontend and Backend then learning Go may not be ideal. There are ways to write code in Go that can be displayed in a browser, for example using &lt;a href="https://github.com/golang/go/wiki/WebAssembly"&gt;WebAssembly&lt;/a&gt; but this is a new technology that is not widely adopted yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Literature&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Depending on your experience and the problem you're trying to solve perhaps the documentation available is not enough, and popular resources like Stackoverflow (and its &lt;a href="https://stackoverflow.com/collectives/go"&gt;Go Collective&lt;/a&gt;) could not provide the right answer.&lt;/p&gt;

&lt;p&gt;Although to date there is a lot of content available covering most of the things related to Go, in some specific cases there's a learning curve that you will have to go through before being able to reach to a solution to some problems, some common examples can be things like Project Layout, Accessing Datastores or Frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  What are the pros?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Easy to learn&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Easy&lt;/em&gt; is relative, if Go is your first programming language then it is going to take you longer to learn it compared to someone with programming experience, however because of the way the language was designed, the amount of keywords and ways to do things is finite even if this is your first language it shouldn't take you that long when using the right literature.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Friendly Community&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are different ways to reach out the Go community, like &lt;a href="http://invite.slack.golangbridge.org/"&gt;GophersSlack&lt;/a&gt; or &lt;a href="https://www.reddit.com/r/golang/"&gt;Reddit&lt;/a&gt;; there's also the yearly &lt;a href="https://www.gophercon.com/"&gt;GopherCon conference&lt;/a&gt; and depending on where you live maybe there's a MeetUp group or a local conference as well.&lt;/p&gt;

&lt;p&gt;Whatever way you prefer to interact with the community you can rest assured there's always someone willing to help you and answer any questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backend-friendly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Also a con but depending on your career goals it could be a pro, this is because Go is a great language for Backend-related projects like CLI tools and Web Services.&lt;/p&gt;

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

&lt;p&gt;Go is one of my favorite programming languages, I like it because it provides features I consider necessary like creating a single binary as the final artifact, a garbage collector and static typing; those are not Go-only features by any means but in Go those are provided without any extra baggage like in other languages.&lt;/p&gt;

&lt;p&gt;Regarding support and packages available, the amount of them nowadays is vast compared to few years ago, and because of that there's a small risk when choosing Go.&lt;/p&gt;

&lt;p&gt;Go is not perfect, dependency management and &lt;a href="https://mariocarrion.com/2021/05/11/golang-microservices-handling-errors.html"&gt;error handling&lt;/a&gt; are some of the most common complaints I hear all the time; I personally like the way errors are implemented but I do see some improvements needed when dealing with dependencies and versioning.&lt;/p&gt;

&lt;p&gt;In the end I think Go is worth learning and giving a try, it could be a differentiator when building Microservices or CLI tools because of the features already included in the standard library as well as the way you could distribute your program as a single binary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended reading
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This following list includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price &lt;strong&gt;is not&lt;/strong&gt; affected at all by using those links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you're looking to sink your teeth into more Go-related topics I recommend the following books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3eQdVpR"&gt;Get Programming with Go&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3bgq5GN"&gt;Go in Practice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3qgZmyf"&gt;Go in Action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/30euJ1U"&gt;Go Web Programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3uX2in5"&gt;Go Programming Blueprints - Second Edition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3rkr3ro"&gt;The Go Programming Language&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
    </item>
    <item>
      <title>Building Microservices in Go: Searching with Elasticsearch</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Thu, 05 Aug 2021 17:21:25 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-searching-with-elasticsearch-2nia</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-searching-with-elasticsearch-2nia</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price &lt;strong&gt;is not&lt;/strong&gt; affected at all by using those links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Elasticsearch?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.elastic.co/what-is/elasticsearch"&gt;Source&lt;/a&gt; (emphasis mine):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;... is a distributed, free and open &lt;strong&gt;search and analytics engine&lt;/strong&gt; for all types of data, including textual, numerical, geospatial, structured, and unstructured.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Elasticsearch is the central component of the Elastic Stack, commonly known as &lt;em&gt;ELK&lt;/em&gt;, this stack consists of the following services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;E&lt;/code&gt;: Elasticsearch,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;L&lt;/code&gt;: Logstash, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;K&lt;/code&gt;: Kibana.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Elasticsearch is a well known tool, already supported by all three big cloud providers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Amazon Web Services has &lt;a href="https://aws.amazon.com/elasticsearch-service/"&gt;Managed Elasticsearch&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Google Cloud Provider has &lt;a href="https://www.elastic.co/partners/google-cloud"&gt;Elastic Cloud&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;Microsoft Azure has &lt;a href="https://azure.microsoft.com/en-us/overview/linux-on-azure/elastic/"&gt;Elastic Cloud&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Using Elasticsearch in Go
&lt;/h2&gt;

&lt;p&gt;There are two two popular packages for interacting with Elasticsearch in Go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/elastic/go-elasticsearch/v7"&gt;github.com/elastic/go-elasticsearch&lt;/a&gt;: the official Go package supported by Elastic, and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pkg.go.dev/github.com/olivere/elastic/v7"&gt;github.com/olivere/elastic&lt;/a&gt;: unofficial package, well-known in the community.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which one should we choose?&lt;/p&gt;

&lt;p&gt;Both of those packages are well supported and production ready, however between the two of them I'm leaning towards using &lt;code&gt;elastic/go-elasticsearch&lt;/code&gt; instead of &lt;code&gt;olivere/elastic&lt;/code&gt; this is because of the comment made by &lt;a href="https://github.com/olivere"&gt;Oliver Eilhard&lt;/a&gt; (the author of &lt;code&gt;olivere/elastic&lt;/code&gt;) on &lt;a href="https://github.com/olivere/elastic/issues/1240"&gt;Github&lt;/a&gt; where he mentions that perhaps a &lt;code&gt;v8&lt;/code&gt; of that package will not be available, that could be an issue if you're planning to upgrade to Elasticsearch Version 8 when that version is available.&lt;/p&gt;

&lt;p&gt;To be fair, to date, the work done by Oliver Eilhard simplifies a lot of the things needed when interacting with the Elasticsearch API which otherwise would have to be explicitly indicated when using the official one, this is because the way &lt;code&gt;olivere/elastic/v7&lt;/code&gt; is implemented it literally covers all the possible options available in the official API and because it's implemented using a &lt;a href="https://en.wikipedia.org/wiki/Fluent_interface"&gt;fluent-like API&lt;/a&gt; its usage and default values are predefined from the beginning.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/6f642254d90096a9b07cde42a9ace45ea02a4b99"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;elastic/go-elasticsearch&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;For implementing the Elasticsearch datastore we are going to follow the &lt;a href="https://mariocarrion.com/2021/04/04/golang-microservices-repository-pattern.html"&gt;Repository Pattern&lt;/a&gt; to update our "To Do Microservice". We will define a new &lt;code&gt;elasticsearch&lt;/code&gt; package with a new type, it will include the corresponding logic needed for indexing, searching as well as deleting records. This type will be called as part of the already existing &lt;code&gt;service.Task&lt;/code&gt;, finally we will expose this feature to our clients via a new HTTP API for searching tasks.&lt;/p&gt;

&lt;p&gt;The code in practice, for indexing, looks more or less like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;

    &lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;indexedTask&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;IsDone&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsDone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;DateStart&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;DateDue&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Due&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;esv7api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IndexRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;DocumentID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Refresh&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ioutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Discard&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And for searching it would look similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
            &lt;span class="s"&gt;"match"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
                &lt;span class="s"&gt;"description"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
            &lt;span class="s"&gt;"match"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
                &lt;span class="s"&gt;"priority"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
            &lt;span class="s"&gt;"match"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
                &lt;span class="s"&gt;"is_done"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;isDone&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
            &lt;span class="s"&gt;"query"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
                &lt;span class="s"&gt;"bool"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
                    &lt;span class="s"&gt;"should"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
            &lt;span class="s"&gt;"query"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Buffer&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;esv7api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SearchRequest&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Hits&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Hits&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Source&lt;/span&gt; &lt;span class="n"&gt;indexedTask&lt;/span&gt; &lt;span class="s"&gt;`json:"_source"`&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"hits"`&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="s"&gt;`json:"hits"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewDecoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hits&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;hits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hits&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hits&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Description&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Due&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateDue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DateStart&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UTC&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In both cases please refer to the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/6f642254d90096a9b07cde42a9ace45ea02a4b99/internal/elasticsearch/task.go"&gt;original implementation&lt;/a&gt; for concrete details, like I mentioned before there's also a &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/6f642254d90096a9b07cde42a9ace45ea02a4b99/internal/elasticsearch/task.go#L85-L108"&gt;&lt;code&gt;Delete&lt;/code&gt; method&lt;/a&gt; meant to be called when deleting previously indexed Tasks.&lt;/p&gt;

&lt;p&gt;To &lt;em&gt;connect&lt;/em&gt; those calls we need to update our &lt;a href="https://mariocarrion.com/2021/04/11/golang-microservices-application-domain-services.html"&gt;&lt;code&gt;service&lt;/code&gt; type&lt;/a&gt; to explicitly call the &lt;em&gt;Search Store&lt;/em&gt; to execute the new actions we already defined; in future posts I will cover how to do this using events instead of explicitly calling stores directly in the service implementation.&lt;/p&gt;

&lt;p&gt;For example the &lt;code&gt;service.Task&lt;/code&gt; type will be doing something like the following in &lt;code&gt;Create&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Create stores a new record.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;

    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dates&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: New Search call to index and store records&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar calls are going to be added to index and a new method for searching records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;By&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isDone&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// XXX: Excluding OpenTelemetry and error checking for simplicity&lt;/span&gt;

    &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isDone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to the other datastore used by this &lt;code&gt;service.Task&lt;/code&gt; we also use &lt;em&gt;Dependency Injection&lt;/em&gt; to refer to the concrete initialized &lt;code&gt;elasticsearch.Task&lt;/code&gt; store.&lt;/p&gt;

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

&lt;p&gt;Elasticsearch is a powerful tool that allows searching records in multiple different ways, it scales horizontally and supports multiple ways to index and search values, for example when using text-based fields it could transform numbers into words to allow searching both the actual literal number and the humanized way to express the value.&lt;/p&gt;

&lt;p&gt;Similarly it allows scoring fields to sort them depending on how many matches they provide giving you the flexibility to display those first by &lt;em&gt;popularity&lt;/em&gt;, as well as other popular features like fuzzy searching that match records related to the searched terms.&lt;/p&gt;

&lt;p&gt;One thing to keep in mind when using Elasticsearch is that sometimes major version upgrades bring behavior-like breaking changes even if the API is still the same.&lt;/p&gt;

&lt;p&gt;Elasticsearch includes more than what I mentioned above it's a really powerful tool that could also be used for analytics, it could be overwhelming to use for sure but it's a tool that should not be ignored.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to sink your teeth into more Elasticsearch-related topics I recommend the following books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3jH7EQc"&gt;Mastering Elasticsearch 5.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3ykZiCa"&gt;Relevant Search: With applications for Solr and Elasticsearch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3yk4WnV"&gt;Elasticsearch in Action &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3Aqh9Jw"&gt;Designing Data-Intensive Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go: Graceful Shutdown</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Thu, 29 Jul 2021 21:23:02 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-graceful-shutdown-4adf</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-graceful-shutdown-4adf</guid>
      <description>&lt;p&gt;When building any &lt;em&gt;long-term running&lt;/em&gt; process, like a webserver or a program importing data, we should consider providing a way to gracefully shut it down, the idea behind this is to provide a way to exit the process cleanly, to clean up resources and to properly cancel that said running process.&lt;/p&gt;

&lt;p&gt;The steps to support &lt;code&gt;Graceful Shutdown&lt;/code&gt; in Go consist of two steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Listen for OS signals, and&lt;/li&gt;
&lt;li&gt;Handle those signals.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Go those signals are provided by the &lt;a href="https://pkg.go.dev/os/signal"&gt;&lt;code&gt;os/signal&lt;/code&gt; package&lt;/a&gt;. Starting with &lt;a href="https://mariocarrion.com/2021/02/17/what-is-new-in-go-1-16.html"&gt;Go 1.16&lt;/a&gt; the way I like to implement &lt;em&gt;Graceful Shutdown&lt;/em&gt; is by using &lt;code&gt;os/signal.NotifyContext&lt;/code&gt;, this function provides an idiomatic way to propagate cancellation when using goroutines, which is usually the case when dealing with long-term running processes.&lt;/p&gt;

&lt;p&gt;Keep in mind that depending on how our &lt;code&gt;main&lt;/code&gt; package is implemented you may need to refactor it, having the &lt;code&gt;main&lt;/code&gt; function to reach the following objectives:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call a &lt;code&gt;Parse&lt;/code&gt; function, if needed, like &lt;code&gt;flag.Parse()&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;Call a &lt;code&gt;run&lt;/code&gt;-like function.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; function is the one orchestrating all the different types, initializing everything, connecting all the dots and perhaps using explicit &lt;em&gt;Dependency Injection&lt;/em&gt;, and more importantly it may run a few goroutines to implement the call to &lt;code&gt;signal.NotifyContext&lt;/code&gt; that in the end is going to handle the logic for implementing &lt;em&gt;Graceful Shutdown&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Let's look at some concrete examples.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;signal.NotifyContext&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Starting in Go 1.16 &lt;code&gt;signal.NotifyContext&lt;/code&gt; is the way I like to recommend when handling signals, this replaces the previous way where a channel was required.&lt;/p&gt;

&lt;p&gt;For example having the same &lt;code&gt;main()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;errC&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;errC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"exiting..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using &lt;code&gt;signal.Notify&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;errC&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;sc&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interrupt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGQUIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"waiting for signal..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;sc&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signal received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errC&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And when using &lt;code&gt;signal.NotifyContext&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;errC&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stop&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotifyContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Interrupt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGTERM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SIGQUIT&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"waiting for signal..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"signal received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errC&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice both of them work achieve the same goal because both of them are meant to listen to signals, however the biggest difference is that &lt;code&gt;signal.NotifyContext&lt;/code&gt; provides a context &lt;code&gt;ctx&lt;/code&gt; that could be used for creating more complex propagation rules (like timeouts for example) that we can use to cancel other goroutines, instead of doing more work manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Graceful Shutdown in HTTP Servers
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/76509a58cabf95bb8329da4e8bf41986885ba814"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Included in the standard library, in &lt;code&gt;net/http&lt;/code&gt;, Go includes its own HTTP Server in &lt;a href="https://pkg.go.dev/net/http#Server"&gt;&lt;code&gt;net/http.Server&lt;/code&gt;&lt;/a&gt;, this server defines a method called &lt;a href="https://pkg.go.dev/net/http#Server.Shutdown"&gt;&lt;code&gt;Shutdown&lt;/code&gt;&lt;/a&gt; meant to be called when the server is supposed to exit and it shutdowns the server gracefully.&lt;/p&gt;

&lt;p&gt;If we use the snippet we defined above we can write our code to handle &lt;em&gt;Graceful Shutdown&lt;/em&gt; for HTTP servers in &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/76509a58cabf95bb8329da4e8bf41986885ba814/cmd/rest-server/main.go#L117-L150"&gt;the following way&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;    &lt;span class="c"&gt;// ... other code initializing things used by this HTTP server&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutdown signal received"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;ctxTimeout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;stop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;

        &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetKeepAlivesEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctxTimeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;errC&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutdown completed"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Listening and serving"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// "ListenAndServe always returns a non-nil error. After Shutdown or Close, the returned error is&lt;/span&gt;
        &lt;span class="c"&gt;// ErrServerClosed."&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrServerClosed&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;errC&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The goal of implementing &lt;em&gt;Graceful Shutdowns&lt;/em&gt; is to allow defining some clean-up steps when dealing with a long-running process, in cases where perhaps we need to commit some database transactions, remove some used files or maybe trigger an event to indicate some other process should take over the subsequent events.&lt;/p&gt;

</description>
      <category>go</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go: Containerization using Docker</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Thu, 22 Jul 2021 21:34:49 +0000</pubDate>
      <link>https://dev.to/mariocarrion/microservices-in-go-containerization-using-docker-2obo</link>
      <guid>https://dev.to/mariocarrion/microservices-in-go-containerization-using-docker-2obo</guid>
      <description>&lt;p&gt;In the past I covered Docker from different point of views, including creating &lt;a href="https://mariocarrion.com/2016/10/31/small-go-docker-image.html"&gt;small docker images&lt;/a&gt;, &lt;a href="https://mariocarrion.com/2019/01/04/go-docker-private-repos-gitlab-ci.html"&gt;building private Go packages with GitlabCI&lt;/a&gt; as well as using it for &lt;a href="https://mariocarrion.com/2021/03/14/golang-package-testing-datastores-ory-dockertest.html"&gt;integration testing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time I will discuss briefly a few cloud providers (and their services) supporting Docker images, the most recent changes Docker added a few years ago to enable &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;multi-stage builds&lt;/a&gt; for building small images and how to use docker-compose for local development.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Docker?
&lt;/h2&gt;

&lt;p&gt;From the &lt;a href="https://www.docker.com/get-started"&gt;official site&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;...is a tool designed to make it easier to create, deploy, and run applications by using containers. Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and deploy it as one package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those containers are created after instantiating &lt;em&gt;Docker Images&lt;/em&gt;, those images need &lt;em&gt;Docker Registries&lt;/em&gt; for distributing those same images to different users, the most popular &lt;em&gt;Docker Registries&lt;/em&gt; at the moment for hosting docker images include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://hub.docker.com/"&gt;DockerHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ecr/"&gt;Amazon Elastic Container Registry (ECR)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/container-registry"&gt;Google Cloud Container Registry&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can still have the option to run a registry on-premise if needed. For orchestrating those &lt;em&gt;Docker Containers&lt;/em&gt; some of the most popular cloud-based provider services available at the moment are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://cloud.google.com/kubernetes-engine"&gt;Google Kubernetes Engine (GKE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/ecs/"&gt;Amazon Elastic Container Service (ECS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://aws.amazon.com/eks/"&gt;Amazon Elastic Kubernetes Service (EKS)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to use multi-stage builds?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/4b39fe091bc38dfeee9f1513bef24a56fe7f4768"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The key parts to use multi-stage builds are to name the image, or images, to use and then call those images in subsequent calls. Please refer to the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/4b39fe091bc38dfeee9f1513bef24a56fe7f4768/build/rest-server/Dockerfile"&gt;original Dockerfile&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; golang:1.16.2-alpine3.13 AS builder&lt;/span&gt;

&lt;span class="c"&gt;# ... commands are called here ...&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; alpine:3.13 AS certificates&lt;/span&gt;

&lt;span class="c"&gt;# ... more commands are called here ...&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; scratch&lt;/span&gt;

&lt;span class="c"&gt;# We refer to the previous stages, to copy the artifacts we created in previous stages.&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=certificates /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/rest-server ./bin/rest-server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case we are using two images in three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;builder&lt;/code&gt;: it is used for building the binaries,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;certificates&lt;/code&gt;: it is used for installing the required certificates, and&lt;/li&gt;
&lt;li&gt;Last one, we are copying the files we need from the other two to finally create the image.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that we can generate the smallest docker image we can actually have for our use case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Docker Compose for local development
&lt;/h2&gt;

&lt;p&gt;When developing locally we could either run the needed services manually or use something like &lt;code&gt;docker-compose&lt;/code&gt;, this really depends on your personal preference, I like running the docker containers manually instead of depending on docker-compose, the reason for this is that, to date, there's no way to really &lt;em&gt;depend&lt;/em&gt; on a service and wait until that one is completely initialized without adding a third-party program to handle that.&lt;/p&gt;

&lt;p&gt;To rephrase it, some containers take longer to initialize and if there is a service depending on them it will start first then and it will fail because the ones that it depends on are still not ready.&lt;/p&gt;

&lt;p&gt;To handle that limitation when using &lt;code&gt;docker-compose&lt;/code&gt; we can re-run those containers after the ones that fail, using our &lt;em&gt;To-Do Microservice&lt;/em&gt; &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/4b39fe091bc38dfeee9f1513bef24a56fe7f4768/docker-compose.yml"&gt;&lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;/a&gt; file for a concrete example, we do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Execute &lt;code&gt;docker-compose up&lt;/code&gt;, this step will start all the required services with their corresponding containers, we expect the &lt;em&gt;api&lt;/em&gt; service to fail because the &lt;code&gt;postgres&lt;/code&gt; service takes longer to start.&lt;/li&gt;
&lt;li&gt;If we run &lt;code&gt;docker-compose up api&lt;/code&gt; only, then the &lt;em&gt;api&lt;/em&gt; service will start successfully but we won't be able to interact with it because the database schema is not up to date, for that we need to run the database migrations.&lt;/li&gt;
&lt;li&gt;Running &lt;code&gt;docker-compose run api migrate -path /api/migrations/ -database postgres://user:password@postgres:5432/dbname?sslmode=disable up&lt;/code&gt; will complete the step of migrating the database to the new version and with that we finally have everything working correctly.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Using containers is not something new but Docker popularized and made it easier for everybody to create and use those containers, over the years cloud service providers, like Amazon and Google Cloud, started supporting those artifacts and integrated them into their services, they even implemented their own versions of popular orchestration tools for containers, like &lt;a href="https://aws.amazon.com/ecs/"&gt;Amazon Elastic Container Service (ECS)&lt;/a&gt; and &lt;a href="https://cloud.google.com/kubernetes-engine"&gt;Google Kubernetes Engine (GKE)&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Using Docker and containers is not a requirement for Microservices but using that together with orchestration tools could result in a good usage of the infrastucture resources being used to make those said Microservices live.&lt;/p&gt;

</description>
      <category>go</category>
      <category>docker</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go:  OpenTelemetry</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Thu, 15 Jul 2021 17:24:19 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-opentelemetry-4i8d</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-opentelemetry-4i8d</guid>
      <description>&lt;p&gt;&lt;a href="https://mariocarrion.com/2021/05/13/golang-microservices-opentelemetry.html" rel="noopener noreferrer"&gt;Original link&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is OpenTelemetry?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://opentelemetry.io/docs/concepts/what-is-opentelemetry/" rel="noopener noreferrer"&gt;Source&lt;/a&gt; (emphasis mine):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;OpenTelemetry is a set of APIs, SDKs, tooling and integrations that are designed for the creation and management of telemetry data such as &lt;strong&gt;traces, metrics, and logs&lt;/strong&gt;. The project provides a &lt;strong&gt;vendor-agnostic&lt;/strong&gt; implementation that can be configured to send telemetry data to the backend(s) of your choice.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In a way &lt;code&gt;OpenTelemetry&lt;/code&gt; was the indirect result of &lt;em&gt;observability&lt;/em&gt;, where the need to monitor multiple services written in different technologies made harder to collect and aggregate observability data.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;OpenTelemetry&lt;/code&gt; does not provide concrete observability backends but rather a &lt;em&gt;standard&lt;/em&gt; way to configure, emit, collect, process and export telemetry data; there are commercially-supported options for those backends, like &lt;a href="https://newrelic.com/solutions/opentelemetry" rel="noopener noreferrer"&gt;NewRelic&lt;/a&gt; and &lt;a href="https://opentelemetry.lightstep.com/" rel="noopener noreferrer"&gt;Lightstep&lt;/a&gt;, as well as some Open Source projects that can be used with it, for this post I'm covering specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://prometheus.io/" rel="noopener noreferrer"&gt;Prometheus&lt;/a&gt; for collecting metrics, and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.jaegertracing.io/" rel="noopener noreferrer"&gt;Jaeger&lt;/a&gt; for collecting traces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenTelemetry support for logs in Go, to date, is &lt;strong&gt;not implemented yet&lt;/strong&gt;, however I'm still showing you how to log data using &lt;a href="https://github.com/uber-go/zap" rel="noopener noreferrer"&gt;Uber's zap&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using OpenTelemetry in Go
&lt;/h2&gt;

&lt;p&gt;At the moment the following is the &lt;code&gt;OpenTelemetry&lt;/code&gt; status regarding the support in Go:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tracing&lt;/strong&gt; Beta&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metrics&lt;/strong&gt; Alpha&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logging&lt;/strong&gt; Not yet implemented&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://opentelemetry.io/docs/go/" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt; describes the steps required for adding OpenTelemetry support to Go programs, although the implementation has not reached a major official release we can still use it in production. There's also a &lt;a href="https://opentelemetry.io/registry/?language=go" rel="noopener noreferrer"&gt;registry&lt;/a&gt; that lists different packages for Go that implement instrumentation or tracing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/baed10d7a1e5a8d2fa7b7883e94e529475db78dc" rel="noopener noreferrer"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;p&gt;For collecting metrics &lt;strong&gt;Prometheus&lt;/strong&gt; will be used. To &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/cmd/rest-server/main.go#L194-L200" rel="noopener noreferrer"&gt;define this exporter&lt;/a&gt; the &lt;a href="https://pkg.go.dev/go.opentelemetry.io/otel/exporters/metric/prometheus" rel="noopener noreferrer"&gt;official OpenTelemetry-Go Prometheus Exporter&lt;/a&gt; is used as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;promExporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;prometheus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewExportPipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prometheus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted for brevity&lt;/span&gt;
&lt;span class="n"&gt;global&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetMeterProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;promExporter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MeterProvider&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exporter implements &lt;a href="https://pkg.go.dev/go.opentelemetry.io/otel/exporters/metric/prometheus#Exporter.ServeHTTP" rel="noopener noreferrer"&gt;&lt;code&gt;http.Handler&lt;/code&gt;&lt;/a&gt;, so we can define it as another endpoint part of our HTTP Server, which then Prometheus will be using for polling metric values:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/metrics"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;promExporter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One important thing about this is that because Prometheus is polling values from our service we must indicate what address and port to use, because we are using docker there's a &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/docs/prometheus.yml" rel="noopener noreferrer"&gt;configuration file&lt;/a&gt; that includes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;to-do-api&lt;/span&gt;
  &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
  &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;host.docker.internal:9234'&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Visiting &lt;code&gt;http://localhost:9090/&lt;/code&gt; should display a user interface like the following after typing a metric and selecting it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flickr.com/photos/mariocarrion/51239882382" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F51239882382_a62bce5540.jpg" alt="OpenTelemetry Prometheus"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracing
&lt;/h3&gt;

&lt;p&gt;For collecting metrics &lt;strong&gt;Jaeger&lt;/strong&gt; will be used. Compared to the Metrics one, &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/cmd/rest-server/main.go#L204-L221" rel="noopener noreferrer"&gt;defining this exporter&lt;/a&gt; is a slightly more elaborated. It requires the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;jaegerEndpoint&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"JAEGER_ENDPOINT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;jaegerExporter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRawExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithCollectorEndpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jaegerEndpoint&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSDKOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSampler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AlwaysSample&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
    &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithProcessFromEnv&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: error omitted for brevity&lt;/span&gt;

&lt;span class="n"&gt;tp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewTracerProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSampler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AlwaysSample&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
    &lt;span class="n"&gt;sdktrace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithSyncer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jaegerExporter&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetTracerProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;otel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCompositeTextMapPropagator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TraceContext&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;propagation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Baggage&lt;/span&gt;&lt;span class="p"&gt;{}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defining that is the first step for having complete tracing support in our program, next we have to define &lt;a href="https://opentelemetry.io/docs/go/instrumentation/#creating-spans" rel="noopener noreferrer"&gt;&lt;em&gt;Spans&lt;/em&gt;&lt;/a&gt;, either manually or automatically depending on the existing wrapper we are planning to use for whatever we want to trace; in our case we are doing it manually.&lt;/p&gt;

&lt;p&gt;For example in the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/internal/postgresql" rel="noopener noreferrer"&gt;&lt;code&gt;postgresql&lt;/code&gt; package&lt;/a&gt; each method of each type defines instructions like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpanFromContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;name&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="c"&gt;// If needed: N calls to "span.SetAttributes(...)"&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example in &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/internal/postgresql/task.go#L28-L31" rel="noopener noreferrer"&gt;&lt;code&gt;postgres.Task.Create&lt;/code&gt;&lt;/a&gt;, we have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpanFromContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Create"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetAttributes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"db.system"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"postgresql"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/open-telemetry/opentelemetry-specification" rel="noopener noreferrer"&gt;&lt;code&gt;OpenTelemetry&lt;/code&gt; specification&lt;/a&gt; defines a few conventions regarding attribute names and supported values, so the attribute &lt;code&gt;db.system&lt;/code&gt; we used above is part of the &lt;a href="https://github.com/open-telemetry/opentelemetry-specification/blob/c254737670b2ba6bdb2eb287e3e0541e2092ed6b/specification/trace/semantic_conventions/database.md" rel="noopener noreferrer"&gt;Database conventions&lt;/a&gt;; in some cases the &lt;a href="https://pkg.go.dev/go.opentelemetry.io/otel/semconv" rel="noopener noreferrer"&gt;&lt;code&gt;go.opentelemetry.io/otel/semconv&lt;/code&gt;&lt;/a&gt; package defines constants we can use, but this is not always the case so keep an eye out.&lt;/p&gt;

&lt;p&gt;Similarly the equivalent &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/internal/service/task.go#L34-L35" rel="noopener noreferrer"&gt;&lt;code&gt;service.Task.Create&lt;/code&gt;&lt;/a&gt; method does the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SpanFromContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Tracer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Task.Create"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is so we can record the call from each layer to measure how much time it took to complete as well as any possible errors that happen. Visiting &lt;code&gt;http://localhost:16686/search&lt;/code&gt; should display a user interface like the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flickr.com/photos/mariocarrion/51241654445/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F51241654445_34e45213a6.jpg" alt="OpenTelemetry Jaeger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After clicking "Find Traces" we should see something like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.flickr.com/photos/mariocarrion/51239890192/" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Flive.staticflickr.com%2F65535%2F51239890192_38dbf5ffdd.jpg" alt="OpenTelemetry Jaeger"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where each &lt;em&gt;Span&lt;/em&gt; is a layer that describes the interactions taken by the whole call. The interesting thing about &lt;code&gt;OpenTelemetry&lt;/code&gt; and &lt;em&gt;spans&lt;/em&gt; is that if there are interactions that include other OpenTelemetry-enabled calls, we could &lt;em&gt;join&lt;/em&gt; them to see the full interaction between all of them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Logs
&lt;/h3&gt;

&lt;p&gt;Although &lt;code&gt;OpenTelemetry&lt;/code&gt; does not support logs in Go yet, logging certain messages should be considered when Building Microservices; the approach I like to recommend is to define a logger instance and then when needed pass it around as an argument when initializating concrete types, the package we are going to be using is &lt;a href="https://github.com/uber-go/zap" rel="noopener noreferrer"&gt;&lt;code&gt;uber-go/zap&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our code implements &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/baed10d7a1e5a8d2fa7b7883e94e529475db78dc/cmd/rest-server/main.go#L66-L78" rel="noopener noreferrer"&gt;a middleware&lt;/a&gt; to log all requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewProduction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sync&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;middleware&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandlerFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"time"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
            &lt;span class="n"&gt;zap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServeHTTP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which then we use to wrap the muxer and therefore all the handlers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="c"&gt;// ... other fields ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;&lt;code&gt;OpenTelemetry&lt;/code&gt;, for Go specifically, is a work in progress, it's definitely a good idea but it is hard to keep your own code up to date with the minor releases, because those happen to break API from time to time. For long running projects I'd recommend to wait until a major version is released, otherwise finding a non-OpenTelemetry option may make more sense.&lt;/p&gt;

&lt;p&gt;I will continue monitoring the progress of this project in future posts, until then I will talk to you later.&lt;/p&gt;

</description>
      <category>go</category>
      <category>microservices</category>
      <category>opentelemetry</category>
    </item>
    <item>
      <title>Building Microservices in Go: REST APIs: Implementing and Dealing with errors</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Thu, 08 Jul 2021 20:12:00 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-implementing-and-dealing-with-errors-5gpc</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-implementing-and-dealing-with-errors-5gpc</guid>
      <description>&lt;p&gt;When building any software, specifically Microservices, there's something we should always be aware of, something that is going to happen no matter what: &lt;strong&gt;errors&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Failures are always something we have to consider when building new software products, it's &lt;em&gt;part of the territory&lt;/em&gt;  and there's no way around it, specially when building distributed systems.&lt;/p&gt;

&lt;p&gt;The problem &lt;strong&gt;is not failing&lt;/strong&gt; but rather the lack of planning regarding monitoring and reacting to those failures.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction to errors
&lt;/h2&gt;

&lt;p&gt;Errors in Go are simple in a sense any type implementing the &lt;a href="https://blog.golang.org/error-handling-and-go#TOC_2."&gt;error interface&lt;/a&gt; is considered an error, the idea with errors is to detect them, do something with them and if needed &lt;em&gt;bubble them up&lt;/em&gt; so the callers can also do something with them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// something happens&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In &lt;a href="https://golang.org/doc/go1.13#error_wrapping"&gt;Go 1.13&lt;/a&gt; a few extra methods were added to the &lt;code&gt;errors&lt;/code&gt; package to handle identifying and working errors in a better way, specifically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://golang.org/pkg/errors/#Is"&gt;errors.Is&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of comparing a sentinel error using the &lt;code&gt;==&lt;/code&gt; operator we can use something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrUnexpectedEOF&lt;/span&gt; &lt;span class="c"&gt;// Before&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrUnexpectedEOF&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// After&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;a href="https://golang.org/pkg/errors/#As"&gt;errors.As&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of explicitly do the type assertion we can use this function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathError&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="c"&gt;// Before&lt;/span&gt;

&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathError&lt;/span&gt; &lt;span class="c"&gt;// After&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;New &lt;code&gt;fmt&lt;/code&gt; verb &lt;code&gt;%w&lt;/code&gt; and &lt;a href="https://golang.org/pkg/errors/#Unwrap"&gt;errors.Unwrap&lt;/a&gt;, with the idea of decorating errors with more details but still keeping the original error intact. For example:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"something failed: %w"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;errors.Unwrap&lt;/code&gt; function is going to make more sense when looking at the code implemented below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing a custom error type with state
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/acbed018c6abb716cd84dffc1777f91dfb5e3dfa"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/acbed018c6abb716cd84dffc1777f91dfb5e3dfa/internal/errors.go"&gt;Our code&lt;/a&gt; implements an error type called &lt;code&gt;internal.Error&lt;/code&gt;, this new type includes state, the idea of this state is to define an &lt;em&gt;Error Code&lt;/em&gt; that we can use to properly render different responses on our HTTP layer. Those different responses are going to be determined by the &lt;em&gt;code&lt;/em&gt; that is included in the error.&lt;/p&gt;

&lt;p&gt;It looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Error represents an error that could be wrapping another error, it includes a code for determining&lt;/span&gt;
&lt;span class="c"&gt;// what triggered the error.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;orig&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;
    &lt;span class="n"&gt;msg&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="n"&gt;code&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the supported error codes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;ErrorCodeUnknown&lt;/span&gt; &lt;span class="n"&gt;ErrorCode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;iota&lt;/span&gt;
    &lt;span class="n"&gt;ErrorCodeNotFound&lt;/span&gt;
    &lt;span class="n"&gt;ErrorCodeInvalidArgument&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those types we can define a few extra functions to help us wrap the original errors, for example our &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/acbed018c6abb716cd84dffc1777f91dfb5e3dfa/internal/postgresql/task.go"&gt;PostgreSQL repository&lt;/a&gt;, uses &lt;code&gt;WrapErrorf&lt;/code&gt; &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/acbed018c6abb716cd84dffc1777f91dfb5e3dfa/internal/postgresql/task.go#L38"&gt;to wrap the error&lt;/a&gt; and add extra details regarding what happend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WrapErrorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorCodeUnknown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"insert task"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then if this error happens, the HTTP layer can react to it and &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/acbed018c6abb716cd84dffc1777f91dfb5e3dfa/internal/rest/rest.go#L16-L35"&gt;render a corresponding response&lt;/a&gt; with the right status code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;renderErrorResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ErrorResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusInternalServerError&lt;/span&gt;

    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ierr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;As&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ierr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"internal error"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;ierr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorCodeNotFound&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusNotFound&lt;/span&gt;
        &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ErrorCodeInvalidArgument&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusBadRequest&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;renderResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;The idea of defining your own errors is to consolidate different ways to handle them, adding state to them allows us to react differently; in our case it would be about rendering different responses depending on the code; but maybe in your use case it could main triggering different alerts or sending messages to different services.&lt;/p&gt;

</description>
      <category>go</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go: REST APIs: Putting it all together</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Sat, 03 Jul 2021 17:00:48 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-putting-it-all-together-17a0</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-putting-it-all-together-17a0</guid>
      <description>&lt;h2&gt;
  
  
  Putting it All Together
&lt;/h2&gt;

&lt;p&gt;The last five posts covered all steps I consider necessary for building the barebones of a REST API, it's not a complete list for sure, it's missing things like deployment, infrastructure and other important details we must consider before making the API live, like scalability, reliability, instrumentation, monitoring and logging, but I will cover those in detail in future posts.&lt;/p&gt;

&lt;p&gt;The following are the concrete decisions I like to follow when building brand new API from scratch:&lt;/p&gt;

&lt;h2&gt;
  
  
  Types to match HTTP resources
&lt;/h2&gt;

&lt;p&gt;This was covered when I talked about &lt;a href="https://mariocarrion.com/2021/04/18/golang-microservices-rest-api-http-handlers.html"&gt;HTTP Handlers&lt;/a&gt; where I mentioned implementing a type to take care of everything related to &lt;em&gt;Tasks&lt;/em&gt;. I like following this guideline because the Go types can easily be categorized and organized accordingly to the HTTP resources they represent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Custom Go Types to describe JSON payloads
&lt;/h2&gt;

&lt;p&gt;Implementing &lt;a href="https://mariocarrion.com/2021/04/28/golang-microservices-rest-api-custom-json-type.html"&gt;Custom JSON Types&lt;/a&gt; is extra work for sure, but I believe making the user experience better for our costumers always matter, sure it's more work for the team in charge of building the APIs but defining more humanized types allows defining much more clearer values for the fields used in the payloads.&lt;/p&gt;

&lt;p&gt;Considering JSON is the &lt;em&gt;de facto&lt;/em&gt; format used for HTTP-based APIs it's important we take advantage of the verbosity we have and be as explicit as we can. The common use case would be to define custom Go types representing enum values in JSON.&lt;/p&gt;

&lt;h2&gt;
  
  
  Document your APIs
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://mariocarrion.com/2021/05/02/golang-microservices-rest-api-openapi3-swagger-ui.html"&gt;OpenAPI&lt;/a&gt; is a great way to create a standardized documentation, we can share it with our costumers as well as with the team in charge of implementing the actual APIs in code.&lt;/p&gt;

&lt;p&gt;The process I described in the post works but I like following a different approach to make sure the different services depending on that documentation don't have circular relationships.&lt;/p&gt;

&lt;p&gt;To do that the actual document is generated &lt;em&gt;outside&lt;/em&gt; of the project implementing it, and the project meant to implement the code can enforce the rules defined by the document as well as reusing the code that was could be generated from it.&lt;/p&gt;

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

&lt;p&gt;Finally, regarding the most difficult topic IMO: &lt;em&gt;versioning&lt;/em&gt;, I like keeping it simple and use path-based APIs; technically in the end using any of the possible options is easy to do thanks to existing gateways that could route requests to different implementations as needed.&lt;/p&gt;

&lt;p&gt;In future posts I will cover more things to consider when &lt;em&gt;Building Microservices in Go&lt;/em&gt;, until then I will talk to you later.&lt;/p&gt;

</description>
      <category>go</category>
      <category>rest</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go: REST APIs - Versioning</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Sun, 27 Jun 2021 16:44:51 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-versioning-165d</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-versioning-165d</guid>
      <description>&lt;h2&gt;
  
  
  What is versioning in software?
&lt;/h2&gt;

&lt;p&gt;Versioning is the idea of identifying a concrete piece of software &lt;em&gt;based on a value&lt;/em&gt;, where this value could used to reference the contract being followed by both the provider of that software as well as the user of that software.&lt;/p&gt;

&lt;p&gt;One example, in the context of REST APIs, would be to identify the fields and types used in the payload of the same resource over time.&lt;/p&gt;

&lt;p&gt;There are multiple ways to create this &lt;em&gt;identity&lt;/em&gt;, from uniquely generated values to sequentially incremented numbers as well as values using release dates. In some cases special rules could be applied to those identifiers, like using odd-numbers to indicate unstable releases.&lt;/p&gt;

&lt;p&gt;Choosing a versioning technique with clearly defined rules is important for both the team in charge of building the product as well as your users to understand &lt;em&gt;how&lt;/em&gt;, &lt;em&gt;when&lt;/em&gt;  and &lt;em&gt;if&lt;/em&gt; a version update is needed, this is where &lt;em&gt;Semantic Versioning&lt;/em&gt; comes in.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price &lt;strong&gt;is not&lt;/strong&gt; affected at all by using those links.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is Semantic Versioning?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://semver.org/"&gt;&lt;em&gt;Semantic Versioning&lt;/em&gt;&lt;/a&gt; is a collection of rules and requirements that determine how version numbers are assigned and incremented. Go, for example, uses it for managing dependencies as part of &lt;a href="https://blog.golang.org/using-go-modules"&gt;Go modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The way it works is by defining a versioning format consisting of three numbers with specific names and rules: &lt;code&gt;X.Y.Z&lt;/code&gt;, where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;X&lt;/code&gt;: represents a major value,&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Y&lt;/code&gt;: represents a minor value, and&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Z&lt;/code&gt;: represents a patch value,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each value indicates &lt;em&gt;how compatible&lt;/em&gt; the version is compared to another one, all of this is better explained by the &lt;a href="https://semver.org/#summary"&gt;Semantic Versioning 2.0 Summary&lt;/a&gt; (emphasis mine):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Given a version number MAJOR.MINOR.PATCH, increment the:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;MAJOR version when you &lt;strong&gt;make incompatible API changes&lt;/strong&gt;,&lt;/li&gt;
&lt;li&gt;MINOR version when you &lt;strong&gt;add functionality in a backwards compatible manner&lt;/strong&gt;, and&lt;/li&gt;
&lt;li&gt;PATCH version when you &lt;strong&gt;make backwards compatible bug fixes&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  How can we implement versioning for REST APIs?
&lt;/h2&gt;

&lt;p&gt;There is no &lt;em&gt;official&lt;/em&gt; recommendation, but different companies in the software industry like to take any of the following approaches, all of them with specific tradeoffs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a &lt;em&gt;path&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Defining &lt;em&gt;subdomains&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Receiving &lt;em&gt;query arguments&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Accepting &lt;em&gt;headers&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Versioning using a path
&lt;/h2&gt;

&lt;p&gt;Differentiate versions by a parent path, which identifies (most of the times) &lt;em&gt;the major version&lt;/em&gt;, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET https://todo.app/**v1**/tasks/{taskId}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET https://todo.app/**v2**/tasks/{taskId}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A real life example of this is the &lt;a href="https://developers.google.com/blogger"&gt;Blogger API&lt;/a&gt;, which at the moment defines two supported APIs with similar resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/blogger/docs/2.0/json/reference"&gt;Version 2&lt;/a&gt; and&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.google.com/blogger/docs/3.0/reference"&gt;Version 3&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example the &lt;code&gt;Blogs: Get&lt;/code&gt; API:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/blogger/docs/2.0/json/reference/blogs/get"&gt;Version 2&lt;/a&gt;: &lt;code&gt;GET https://www.googleapis.com/blogger/v2/blogs/{blogId}&lt;/code&gt; and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/blogger/docs/3.0/reference/blogs/get"&gt;Version 3&lt;/a&gt;: &lt;code&gt;GET https://www.googleapis.com/blogger/v3/blogs/{blogId}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementation details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In Go: each version defines a concrete handler that happens to be using specific paths, requests and response types.&lt;/li&gt;
&lt;li&gt;Not Go: two different microservices using a gateway that uses the path to redirect traffic to specific versions.&lt;/li&gt;
&lt;li&gt;OpenAPI/Swagger: can be used.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Versioning using subdomains
&lt;/h2&gt;

&lt;p&gt;Differentiate versions by subdomain, which identifies (most of the times) &lt;em&gt;the major version&lt;/em&gt;, for example: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET https://**v1**.todo.app/tasks/{taskId}&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET https://**v2**.todo.app/tasks/{taskId}&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Implementation details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They could literally be two different microservices, totally independent of each other.&lt;/li&gt;
&lt;li&gt;OpenAPI/Swagger: can be used.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Versioning using query arguments
&lt;/h2&gt;

&lt;p&gt;Differentiate versions by query arguments, with the possibility to indicate exactly the version to use, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET https://todo.app/tasks/{taskId}?**v=1**&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET https://todo.app/tasks/{taskId}?**v=2**&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example &lt;a href="https://docs.microsoft.com/en-us/azure/devops/integrate/concepts/rest-api-versioning?view=azure-devops"&gt;Microsoft Azure DevOps Services&lt;/a&gt; uses this approach where a way to specify the version would be using something like:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;GET https://dev.azure.com/{organization}/_apis/{area}/{resource}?api-version=1.0&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Implementation details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When using different technologies: a gateway could be used,&lt;/li&gt;
&lt;li&gt;When using the same technologies: complicated to maintain because both may be using the same underlying handler, either a &lt;code&gt;switch&lt;/code&gt;-like style or &lt;code&gt;map&lt;/code&gt;-based functions; or literally implement a new microservice and use a gateway,&lt;/li&gt;
&lt;li&gt;OpenAPI/Swagger: hard to define requests and schemas, but possible, &lt;a href="https://docs.microsoft.com/en-us/rest/api/searchmanagement/management-api-versions"&gt;Microsoft Azure Cognitive Search: api-version&lt;/a&gt; does that.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Versioning using headers
&lt;/h2&gt;

&lt;p&gt;Differentiate versions by values in the HTTP headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using a custom Header:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;GET -H **"Version: &amp;lt;VERSION&amp;gt;"** https://todo.app/tasks/{taskId}&lt;/code&gt;, or &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Using Content Negotiation, for example &lt;a href="https://docs.github.com/en/rest/overview/media-types#request-specific-version"&gt;Github&lt;/a&gt; uses a &lt;a href="https://tools.ietf.org/html/rfc4288#section-3.2"&gt;vendor prefix&lt;/a&gt; to do so:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;GET -H **"Accept: application/vnd.todo.&amp;lt;VERSION&amp;gt;+json"** https://todo.app/tasks/{taskId}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Implementation details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When using different technologies: a gateway could be used,&lt;/li&gt;
&lt;li&gt;When using the same technologies: complicated to maintain because both may be using the same underlying handler, either a &lt;code&gt;switch&lt;/code&gt;-like style or &lt;code&gt;map&lt;/code&gt;-based functions; or literally implement a new microservice and use a gateway,&lt;/li&gt;
&lt;li&gt;OpenAPI/Swagger: hard to define requests and schemas, but possible, &lt;a href="https://github.com/github/rest-api-description/tree/main/descriptions"&gt;Github&lt;/a&gt; does that.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;So what is &lt;em&gt;the best option?&lt;/em&gt; The usual answer: &lt;em&gt;"It depends"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In the end I believe the customer experience matters the most and perhaps taking the simplest approach, like using &lt;em&gt;subdomains&lt;/em&gt; or &lt;em&gt;paths&lt;/em&gt;, makes adopting your API easier for your customers increasing your market-share.&lt;/p&gt;

&lt;p&gt;Besides selecting a way to version HTTP REST APIs, the important thing to know is how and when to introduce breaking changes, the approach I like taking is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Before&lt;/strong&gt; adding a new major version:

&lt;ul&gt;
&lt;li&gt;Delay &lt;strong&gt;v1&lt;/strong&gt; as much as possible, literally &lt;em&gt;stay with v0 "forever"&lt;/em&gt;, or at least make it clear to your customers breaking changes may be expected.&lt;/li&gt;
&lt;li&gt;Try to make your changes additive only and deprecate old ones.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;While&lt;/strong&gt; dealing with multiple versions. Consider a hybrid, for example &lt;em&gt;Paths&lt;/em&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;v1&lt;/em&gt;: &lt;code&gt;GET https://todo.app/v1/tasks/{taskId}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;v1&lt;/em&gt;: &lt;strong&gt;deprecated&lt;/strong&gt; &lt;code&gt;PUT https://todo.app/v1/tasks/{taskId}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;v2&lt;/em&gt;: &lt;code&gt;PUT https://todo.app/v2/tasks/{taskId}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;After&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Encourage users to upgrade to new version by clearly indicating new features and capabilities,&lt;/li&gt;
&lt;li&gt;Provide a way to automatically upgrade, and&lt;/li&gt;
&lt;li&gt;Give a concrete deadline, plan deprecating older versions, if you can; in some cases building a &lt;em&gt;bridge&lt;/em&gt; API to convert from one to another could be needed.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Recommended Reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to sink your teeth into more REST and Web Programming I recommend the following books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/32yFwFe"&gt;The Design of Web APIs (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/2MQHYmo"&gt;Irresistible APIs (2016)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/30euJ1U"&gt;Go Web Programming (2016)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3n6ztRZ"&gt;REST in Practice (2010)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>rest</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Building Microservices in Go: REST APIs - OpenAPI 3 and Swagger UI</title>
      <dc:creator>Mario Carrion</dc:creator>
      <pubDate>Sat, 19 Jun 2021 22:25:16 +0000</pubDate>
      <link>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-openapi-3-and-swagger-ui-8o1</link>
      <guid>https://dev.to/mariocarrion/building-microservices-in-go-rest-apis-openapi-3-and-swagger-ui-8o1</guid>
      <description>&lt;h2&gt;
  
  
  What is Swagger? OpenAPI?
&lt;/h2&gt;

&lt;p&gt;Swagger/OpenAPI allows us to document and collaborate with our users, specifically it allows to define the resources, parameters, types, fields and everything that describes the APIs we are building. Swagger and OpenAPI are two different things, it's better explained on &lt;a href="https://swagger.io/blog/api-strategy/difference-between-swagger-and-openapi/"&gt;the original blog post&lt;/a&gt;, but the idea is basically this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;OpenAPI&lt;/em&gt;: Specification&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Swagger&lt;/em&gt;: Tools for implementing the specification&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; This post includes Amazon affiliate links. If you click on one of them and you make a purchase I'll earn a commission. Please notice your final price &lt;strong&gt;is not&lt;/strong&gt; affected at all by using those links.&lt;/p&gt;

&lt;p&gt;The code used for this post is &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/074bbb9f4d0f79e5bced943c10c56013705969a9"&gt;available on Github&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Implementing OpenAPI 3
&lt;/h2&gt;

&lt;p&gt;Using Swagger 2.0 in Go well-known to be supported by packages like &lt;a href="https://github.com/go-swagger/go-swagger"&gt;github.com/go-swagger/go-swagger&lt;/a&gt; and &lt;a href="https://github.com/swaggo/swag"&gt;github.com/swaggo/swag&lt;/a&gt; however it gets more complicated when trying to use something much more recent like OpenAPI 3, in those cases really we have a few packages we can use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/getkin/kin-openapi"&gt;github.com/getkin/kin-openapi/openapi3&lt;/a&gt;: to generate OpenAPI 3.0 documentation, and&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/deepmap/oapi-codegen"&gt;github.com/deepmap/oapi-codegen&lt;/a&gt;: to generate Go client and server boilerplate from OpenAPI 3 specifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For generating the OpenAPI 3.0 document, we are going to be using the &lt;code&gt;getkin/kin-openapi/openapi3&lt;/code&gt; package, our example already defines &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/internal/rest/open_api.go"&gt;a function that does that for us&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This function is long and it could a turn off for a lot of people, however I like it the way it is because it allows me to explicitly indicate the values I need, there's no magic (like in &lt;code&gt;go-swagger&lt;/code&gt; or &lt;code&gt;swagger/swag&lt;/code&gt; for example), it's a pro/con depending on how you see it because everything it's more manual.&lt;/p&gt;

&lt;p&gt;In the end, the code needed to represent our API will be equivalent to the code written to build that structure. For example, taking the basic OpenAPI details, it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// NewOpenAPI3 instantiates the OpenAPI specification for this service.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewOpenAPI3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Swagger&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;swagger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Swagger&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;OpenAPI&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"3.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Info&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;"ToDo API"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"REST APIs used for interacting with the ToDo Service"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Version&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="s"&gt;"0.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"https://opensource.org/licenses/MIT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;Contact&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Contact&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"https://github.com/MarioCarrion/todo-api-microservice-example"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;Servers&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Servers&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Local development"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;"http://0.0.0.0:9234"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// ... more code ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that function defined and with a &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/cmd/openapi-gen/main.go"&gt;helper binary&lt;/a&gt; we call &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/internal/rest/open_api.go#L11"&gt;&lt;code&gt;go generate&lt;/code&gt;&lt;/a&gt; to build the YAML and JSON files we need to describe our API.&lt;/p&gt;

&lt;p&gt;In practice the code in that &lt;code&gt;cmd/openapi-gen/main.go&lt;/code&gt; looks basically like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;swagger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;rest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewOpenAPI3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c"&gt;// openapi3.json&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;swagger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"openapi3.json"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: explicitly ignoring errors&lt;/span&gt;

    &lt;span class="c"&gt;// openapi3.yaml&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Marshal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;swagger&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"openapi3.yaml"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: explicitly ignoring errors&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last thing is to make those &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/internal/rest/open_api.go#L190-L206"&gt;files available&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;RegisterOpenAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Router&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;swagger&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;NewOpenAPI3&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/openapi3.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ... code here ...&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandleFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/openapi3.yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// ... code here ...&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Methods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodGet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Implementing Swagger UI
&lt;/h2&gt;

&lt;p&gt;We built out OpenAPI 3 files, now as part of our HTTP handlers we are going to allow our users to interact with the &lt;a href="https://github.com/swagger-api/swagger-ui"&gt;Swagger UI&lt;/a&gt; to invoke our API, this is something that you may or not want to have in production, I personally prefer only allowing internal environments to support this UI for testing purposes.&lt;/p&gt;

&lt;p&gt;To support the Swagger UI our your API we need to download all the &lt;a href="https://github.com/swagger-api/swagger-ui/tree/master/dist"&gt;&lt;code&gt;dist&lt;/code&gt; files&lt;/a&gt; from the original repository and then embed them as part of your API as a new handler, for example copying the files over to &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/tree/074bbb9f4d0f79e5bced943c10c56013705969a9/cmd/rest-server/static/swagger-ui"&gt;&lt;code&gt;cmd/rest-server/static/swagger-ui&lt;/code&gt;&lt;/a&gt;, and then embedding those using the new &lt;code&gt;embed&lt;/code&gt; package included in Go 1.16, using something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:embed static&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="n"&gt;embed&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FS&lt;/span&gt;


&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ... other code ...&lt;/span&gt;

    &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;mux&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRouter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;fsys&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"static"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PathPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/static/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StripPrefix&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/static/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FileServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fsys&lt;/span&gt;&lt;span class="p"&gt;))))&lt;/span&gt;

    &lt;span class="n"&gt;srv&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Server&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="c"&gt;// ... other code ...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;srv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With that code in place we will be able to request &lt;code&gt;http://address:port/static/swagger-ui&lt;/code&gt; and load our API using the OpenAPI 3 file we generated previously, one really important thing to change is the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/cmd/rest-server/static/swagger-ui/index.html#L42"&gt;&lt;code&gt;index.html&lt;/code&gt; file&lt;/a&gt; to refer to the local &lt;code&gt;openapi3.json&lt;/code&gt; file and perhaps you want to generate that file depending on environment so it always points to the right HTTP URL.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating Client and Serve code from OpenAPI 3
&lt;/h2&gt;

&lt;p&gt;Another interesting thing we can do after generating our OpenAPI 3 documentation is to generate boilerplate that represents Go types matching the original API, for that we use a package we mentioned earlier: &lt;a href="https://github.com/deepmap/oapi-codegen"&gt;github.com/deepmap/oapi-codegen&lt;/a&gt;. The way it works is like this:&lt;/p&gt;

&lt;p&gt;We install the generator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;github&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;deepmap&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;oapi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;codegen&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;oapi&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;codegen&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;v1&lt;/span&gt;&lt;span class="m"&gt;.5.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then using &lt;code&gt;go generate&lt;/code&gt; when generate &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/internal/rest/open_api.go#L12-L13"&gt;our types&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;//go:generate oapi-codegen -package openapi3 -generate types  -o ../../pkg/openapi3/task_types.gen.go openapi3.yaml&lt;/span&gt;
&lt;span class="c"&gt;//go:generate oapi-codegen -package openapi3 -generate client -o ../../pkg/openapi3/client.gen.go     openapi3.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which in our example will create a bunch of types in the &lt;code&gt;pkg&lt;/code&gt; package that then we can use to programmatically build some code to interact with out API, like the &lt;a href="https://github.com/MarioCarrion/todo-api-microservice-example/blob/074bbb9f4d0f79e5bced943c10c56013705969a9/cmd/cli/main.go"&gt;following example&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClientWithResponses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://0.0.0.0:9234"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// XXX: explicitly ignoring errors&lt;/span&gt;

    &lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Priority_low&lt;/span&gt;

    &lt;span class="n"&gt;respC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateTaskWithResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="c"&gt;// XXX: explicitly ignoring errors&lt;/span&gt;
        &lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CreateTaskJSONRequestBody&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;openapi3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dates&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newPtrTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
                &lt;span class="n"&gt;Due&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;newPtrTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Hour&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="m"&gt;24&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="n"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;newPtrStr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleep early"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="n"&gt;Priority&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c"&gt;// ... other code ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Parting words
&lt;/h2&gt;

&lt;p&gt;Documenting REST APIs in Go using Swagger 2.0 is relatively well supported and easy to do, there are a few different alternatives, however the concern you may have is that you're depending on technologies that are already old, if you want to explore the most recent alternatives like OpenAPI 3 things get more complicated, because the options are much more manual and really state of the art, which is a fair concern for people looking for long term solutions.&lt;/p&gt;

&lt;p&gt;So what's the best approach? The way I see it is, if you're not willing to invest resources trying out new state-of-the-art tools then using Swagger 2.0 is your answer; however if you're willing to contribute back to the community exploring the OpenAPI 3 options is better because in the end it benefits everybody.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recommended Reading
&lt;/h2&gt;

&lt;p&gt;If you're looking to sink your teeth into more REST and Web Programming I recommend the following books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/32yFwFe"&gt;The Design of Web APIs (2019)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/2MQHYmo"&gt;Irresistible APIs (2016)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/30euJ1U"&gt;Go Web Programming (2016)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3n6ztRZ"&gt;REST in Practice (2010)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>openapi</category>
      <category>swagger</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
