<?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: Manuel Doncel Martos</title>
    <description>The latest articles on DEV Community by Manuel Doncel Martos (@manuelarte).</description>
    <link>https://dev.to/manuelarte</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%2F231181%2Fd1dee2aa-ca0d-43eb-83bc-b3b833f3efe8.jpeg</url>
      <title>DEV Community: Manuel Doncel Martos</title>
      <link>https://dev.to/manuelarte</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manuelarte"/>
    <language>en</language>
    <item>
      <title>Practicing Basic Concepts On Web Security</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Wed, 08 Apr 2026 17:39:56 +0000</pubDate>
      <link>https://dev.to/manuelarte/practicing-basic-concepts-on-web-security-5a9m</link>
      <guid>https://dev.to/manuelarte/practicing-basic-concepts-on-web-security-5a9m</guid>
      <description>&lt;h1&gt;
  
  
  Building (and Breaking) a Vulnerable Web App in Go + Vue.js
&lt;/h1&gt;

&lt;p&gt;As developers, we often learn best by doing, and in cybersecurity, that means not just building secure systems, but also understanding how they break. &lt;/p&gt;

&lt;p&gt;During the last months, I was on charge of explaining some of the OWASP vulnerabilities to my team, and for that I created a vulnerable web application using Go (backend) and Vue.js (frontend), designed to demonstrate some of the most common and dangerous web vulnerabilities.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The project is available here: &lt;a href="https://github.com/manuelarte/gowasp" rel="noopener noreferrer"&gt;https://github.com/manuelarte/gowasp&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;The README includes a step-by-step hands-on exploitation guide.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this post, I’ll walk through the key vulnerabilities implemented in the app and how an attacker can exploit them.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧨 1. SQL Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The vulnerability
&lt;/h3&gt;

&lt;p&gt;SQL Injection occurs when user input is directly concatenated into SQL queries without proper sanitization or parameterization.&lt;/p&gt;

&lt;p&gt;A typical vulnerable pattern 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="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="s"&gt;"SELECT * FROM users WHERE email = '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"' AND password = '"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Exploitation
&lt;/h3&gt;

&lt;p&gt;An attacker can bypass authentication by injecting SQL logic:&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;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;admin' --&lt;/span&gt;
&lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;anything&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This turns the query into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'admin'&lt;/span&gt; &lt;span class="c1"&gt;--' AND password = 'anything'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The password check is commented out, granting access without valid credentials.&lt;/p&gt;

&lt;p&gt;In the vulnerable application, you can practice this vulnerability and try to log in without knowing the password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;p&gt;Always use prepared statements or ORM parameter binding. Never trust raw user input.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧬 2. Mass Assignment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The vulnerability
&lt;/h3&gt;

&lt;p&gt;Mass assignment happens when user-controlled input is directly bound to a struct or model without filtering allowed fields.&lt;/p&gt;

&lt;p&gt;Example:&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;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;r&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;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;User&lt;/code&gt; struct includes sensitive fields like &lt;code&gt;isAdmin&lt;/code&gt;, an attacker can modify them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploitation
&lt;/h3&gt;

&lt;p&gt;A malicious request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"attacker@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"isAdmin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the backend doesn’t explicitly restrict fields, the attacker becomes an admin by assigning himself as admin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;p&gt;Use DTOs (Data Transfer Objects) or explicit field mapping. Never bind request bodies directly to domain models.&lt;/p&gt;




&lt;h2&gt;
  
  
  🔁 3. CSRF (Cross-Site Request Forgery)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The vulnerability
&lt;/h3&gt;

&lt;p&gt;CSRF occurs when authenticated users unknowingly perform actions triggered by malicious websites.&lt;/p&gt;

&lt;p&gt;If your app relies only on cookies for authentication and lacks CSRF protection, it's vulnerable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploitation
&lt;/h3&gt;

&lt;p&gt;An attacker can craft a hidden form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;action=&lt;/span&gt;&lt;span class="s"&gt;"https://yourapp.com/api/delete-account"&lt;/span&gt; &lt;span class="na"&gt;method=&lt;/span&gt;&lt;span class="s"&gt;"POST"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forms&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;submit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the victim is logged in, their browser will send the request with session cookies—deleting their account without consent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;p&gt;Use CSRF tokens and validate them server-side. SameSite cookies help, but are not enough alone.&lt;/p&gt;




&lt;h2&gt;
  
  
  🧩 4. HTML Template Injection
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The vulnerability
&lt;/h3&gt;

&lt;p&gt;When user input is rendered into templates without proper escaping, attackers can inject malicious expressions.&lt;/p&gt;

&lt;p&gt;In Go templates, unsafe usage might look 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="n"&gt;tmpl&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&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;userInput&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And in VueJS it can be used with &lt;code&gt;v-html&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Exploitation
&lt;/h3&gt;

&lt;p&gt;An attacker injects template syntax in part that renders user input.&lt;/p&gt;

&lt;p&gt;In some engines, this can lead to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Data leakage&lt;/li&gt;
&lt;li&gt;Server-side execution&lt;/li&gt;
&lt;li&gt;XSS (if rendered in browser)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Takeaway
&lt;/h3&gt;

&lt;p&gt;Always treat user input as untrusted. Use proper escaping and avoid rendering raw input in templates.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Project Matters
&lt;/h2&gt;

&lt;p&gt;Modern frameworks make it &lt;em&gt;easier&lt;/em&gt; to build applications—but they don’t make them automatically secure. These vulnerabilities are still incredibly common in real-world systems.&lt;/p&gt;

&lt;p&gt;By intentionally building insecure features, this project helps you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand how attacks actually work&lt;/li&gt;
&lt;li&gt;Recognize insecure coding patterns&lt;/li&gt;
&lt;li&gt;Learn how to defend against them effectively&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  🛠️ Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The repository includes a full walkthrough so you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run the vulnerable app locally&lt;/li&gt;
&lt;li&gt;Exploit each vulnerability step by step&lt;/li&gt;
&lt;li&gt;Understand the impact in a safe environment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 &lt;a href="https://github.com/manuelarte/gowasp" rel="noopener noreferrer"&gt;https://github.com/manuelarte/gowasp&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Final Comments
&lt;/h2&gt;

&lt;p&gt;Security is not a feature you apply from the beginning.&lt;/p&gt;

&lt;p&gt;If you can break your own system, you’re already one step closer to building something resilient.&lt;/p&gt;

&lt;p&gt;And if you haven’t tried breaking it yet… someone else eventually will.&lt;/p&gt;




</description>
      <category>go</category>
      <category>web</category>
      <category>security</category>
    </item>
    <item>
      <title>What developers don't get about Idempotence</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Wed, 18 Feb 2026 16:38:03 +0000</pubDate>
      <link>https://dev.to/manuelarte/what-developers-dont-get-about-idempotency-1hgm</link>
      <guid>https://dev.to/manuelarte/what-developers-dont-get-about-idempotency-1hgm</guid>
      <description>&lt;p&gt;❓Quick question: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is a DELETE endpoint that returns &lt;code&gt;404&lt;/code&gt; on subsequent calls idempotent?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you said 'no' because the response changed, this article is for you.&lt;/p&gt;

&lt;p&gt;Idempotence is a concept that is often misunderstood, sometimes even by developers with many years of experience.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Idempotence
&lt;/h1&gt;

&lt;p&gt;If we take the Wikipedia definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So as we can see, it's originally a mathematical concept that got translated to Computer Science.&lt;/p&gt;

&lt;p&gt;In Computer Science, the term idempotence I like to describe it as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Idempotence in computer science is the property of an operation whereby it can be applied multiple times without changing the result beyond the initial application&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Example GET operation
&lt;/h2&gt;

&lt;p&gt;Normally, a GET operation is idempotent, since &lt;strong&gt;it does not imply any change in the database&lt;/strong&gt;. So, for example, you can have an endpoint like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;/api/v1/users&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And it does not matter how many times you call it, it will return the same output and produce no side effect.&lt;/p&gt;

&lt;h2&gt;
  
  
  POST, PUT, PATCH and DELETE operations
&lt;/h2&gt;

&lt;p&gt;This is where the confusion comes from. People by default think that POST, PUT, and PATCH endpoints are not idempotent by definition, and the answer is that it depends on the actual implementation of the endpoints.&lt;/p&gt;

&lt;h3&gt;
  
  
  POST operations
&lt;/h3&gt;

&lt;p&gt;Let's look for example the case of a POST endpoint to create &lt;code&gt;User&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;Imagine that we have the following model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="no"&gt;UUID&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we call the endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; POST api/v1/users

{
  "username": "manuelarte"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Getting a response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"f2f7734c-1082-43cf-9b66-9161349ef154"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manuelarte"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❓Is this endpoint idempotent? &lt;/p&gt;

&lt;p&gt;With this information alone, we cannot determine it yet.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario A: A new user is created
&lt;/h4&gt;

&lt;p&gt;If we call it again with the same input and we get:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c6fab354-c559-460b-a66c-5d0bad8f6aba"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manuelarte"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the endpoint is definitely not idempotent❌, &lt;strong&gt;since it is creating new users for each request with the same data&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario B: Same response as first response
&lt;/h4&gt;

&lt;p&gt;And, what happens if we call the endpoint again with the same data and the response is the same as in the first call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;OK&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"c6fab354-c559-460b-a66c-5d0bad8f6aba"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"manuelarte"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, ✅&lt;strong&gt;the endpoint is idempotent&lt;/strong&gt;, because it's not creating a new entry in the database, and in this case is &lt;em&gt;returning the already existing entry&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;So, it does not matter how many times you call this endpoint with this data, &lt;em&gt;the state remains the same&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This is the scenario that most people understand for idempotence. If you do multiple request with the same data, you always get the same response, same HTTP response code and same body.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scenario C: Consecutive calls returns different response
&lt;/h4&gt;

&lt;p&gt;But, let's imagine that the endpoint returns the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bad&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Request&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"USER_CREATED"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user already created"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now, instead of &lt;code&gt;200&lt;/code&gt;, it is returning &lt;code&gt;400&lt;/code&gt;, and explaining that there is already a user with that username created.&lt;/p&gt;

&lt;p&gt;❓Do you think that this endpoint is, then, idempotent?&lt;/p&gt;

&lt;p&gt;And the answer is (and this is where many senior developers and/or architects get idempotence wrong) that &lt;strong&gt;this implementation is also idempotent&lt;/strong&gt;, because the second and subsequent calls do not change state. In this case, with only one user created.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So idempotence is about the final state in the database, and not about the HTTP verb or HTTP response code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  DELETE endpoints
&lt;/h3&gt;

&lt;p&gt;To clarify more, let's put another example, this time using a &lt;code&gt;DELETE&lt;/code&gt; endpoint:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DELETE /api/v1/users/{id} &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If we call this endpoint with the user &lt;code&gt;id&lt;/code&gt;, then this endpoint is idempotent independently of the response code, because after the first successful deletion, the resource no longer exists, and further calls do not change the state.&lt;/p&gt;

&lt;p&gt;So after that initial call, next calls can have outputs like &lt;code&gt;NO CONTENT 204&lt;/code&gt; or &lt;code&gt;NOT FOUND 404&lt;/code&gt; and the endpoint is still idempotent.&lt;/p&gt;

&lt;p&gt;But you could have an endpoint like this&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DELETE /api/v1/users/last&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That would delete the latest user created, and even that it could potentially return, e.g. &lt;code&gt;NO CONTENT 204&lt;/code&gt; for every call, the endpoint would not be idempotent. &lt;/p&gt;

&lt;p&gt;So, as an example, each call changes which user is considered "last". The first call deletes user 5, the second deletes user 4, and so on. The state changes with each call.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary and takeaways
&lt;/h2&gt;

&lt;p&gt;Hopefully you are able to understand that idempotence is about consecutive calls with the same data leads to no change in the state.&lt;/p&gt;

&lt;p&gt;Understanding that idempotence is about state, not responses, is crucial for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;API Design: Building robust systems that handle retries safely&lt;/li&gt;
&lt;li&gt;Client Implementation: Knowing how to handle different response codes&lt;/li&gt;
&lt;li&gt;Contract Testing: Writing accurate tests for API behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Next time you're designing or consuming an API, remember:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;idempotence = State doesn't change after the first request&lt;/li&gt;
&lt;li&gt;HTTP methods suggest idempotence, but implementation guarantees it&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;idempotence isn't about what the server says—it's about what the server does.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For more references check &lt;a href="https://datatracker.ietf.org/doc/html/rfc9110" rel="noopener noreferrer"&gt;RFC-9110&lt;/a&gt;, and &lt;a href="https://datatracker.ietf.org/doc/draft-ietf-httpapi-idempotency-key-header/" rel="noopener noreferrer"&gt;how to implement idempotence with headers&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>restapi</category>
      <category>learning</category>
      <category>idempotence</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Mon, 26 Jan 2026 18:30:12 +0000</pubDate>
      <link>https://dev.to/manuelarte/-e4a</link>
      <guid>https://dev.to/manuelarte/-e4a</guid>
      <description>&lt;div class="ltag__link"&gt;
  &lt;a href="/manuelarte" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F231181%2Fd1dee2aa-ca0d-43eb-83bc-b3b833f3efe8.jpeg" alt="manuelarte"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://dev.to/manuelarte/elegant-domain-driven-design-objects-in-go-2bhi" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Elegant Domain-Driven Design objects in Go&lt;/h2&gt;
      &lt;h3&gt;Manuel Doncel Martos ・ Jan 19&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#ddd&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#go&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#entity&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#valueobjects&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


</description>
      <category>ddd</category>
      <category>go</category>
      <category>entity</category>
      <category>valueobjects</category>
    </item>
    <item>
      <title>go-kata 01/01-concurrent-aggregator</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Mon, 26 Jan 2026 10:00:09 +0000</pubDate>
      <link>https://dev.to/manuelarte/go-kata-0101-concurrent-aggregator-d2p</link>
      <guid>https://dev.to/manuelarte/go-kata-0101-concurrent-aggregator-d2p</guid>
      <description>&lt;p&gt;A few weeks ago I discovered this GitHub repository &lt;a href="https://github.com/MedUnes/go-kata" rel="noopener noreferrer"&gt;go-kata&lt;/a&gt;, containing some Go exercises that encourage to write idiomatic Go. What caught my attention was the fact that they come with no solutions, just you, the problem, and your Go skills.&lt;/p&gt;

&lt;p&gt;The repository quickly gained traction, and got more than 1k stars⭐ and was mentioned in several social networks, e.g. &lt;a href="https://x.com/golangch/status/2008409551905976791" rel="noopener noreferrer"&gt;X&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I decided to tackle these problems myself and share my solutions in my own &lt;a href="https://github.com/manuelarte/go-kata/tree/solutions" rel="noopener noreferrer"&gt;fork&lt;/a&gt;, hoping to inspire people to try and to refine my approach through community feedback.&lt;/p&gt;

&lt;h2&gt;
  
  
  01-context-cancellation-concurrency/01-concurrent-aggregator
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Problem
&lt;/h3&gt;

&lt;p&gt;The challenge is straightforward but captures a common real-world scenario:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Call two services concurrently, &lt;code&gt;Profile&lt;/code&gt; and &lt;code&gt;Order&lt;/code&gt;, combine their outputs into a single string like &lt;br&gt;
&lt;code&gt;"User: Alice | Orders: 5"&lt;/code&gt;, and handle failures gracefully. &lt;br&gt;
If either service call fails, the entire operation must be interrupted immediately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A more detailed description of the requirements can be found in the &lt;a href="https://github.com/MedUnes/go-kata/tree/master/01-context-cancellation-concurrency/01-concurrent-aggregator" rel="noopener noreferrer"&gt;README.md&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing The Services
&lt;/h3&gt;

&lt;p&gt;Let's start implementing the services. The goal is they can be configurable in a way that they can either return the actual result, or an error, and also how long does it take to get that response.&lt;/p&gt;

&lt;p&gt;So we could have something like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Both services succeed within timeout&lt;/li&gt;
&lt;li&gt;⏱️ Both services timeout&lt;/li&gt;
&lt;li&gt;❌ One service fails while the other succeeds&lt;/li&gt;
&lt;li&gt;🔄 Context cancellation propagates correctly&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For that, and without entering in too much details, I created a &lt;a href="https://github.com/manuelarte/go-kata/blob/solutions/01-context-cancellation-concurrency/01-concurrent-aggregator/services/mock/service.go" rel="noopener noreferrer"&gt;mock service&lt;/a&gt; that I can configure the output and the time.&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="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&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;Response&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&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;Sleep&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="n"&gt;Val&lt;/span&gt;   &lt;span class="n"&gt;T&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="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="n"&gt;GetResponse&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;T&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="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&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="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Response&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="o"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&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;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Val&lt;/span&gt;&lt;span class="p"&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;Response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&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="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;t&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="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;Then I created the &lt;code&gt;profile.Service&lt;/code&gt; and &lt;code&gt;order.Service&lt;/code&gt; using that mock.&lt;/p&gt;

&lt;p&gt;In that way, I can configure the two services to cover those scenarios we mentioned above, e.g:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Profile and order services returns the successful response on time:
&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;timeout&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;2&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="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileSuccessResponse&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="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;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderSuccessResponse&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="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Profile and order services returns the successful response not on time:
&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;timeout&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;2&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="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileSuccessResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&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="n"&gt;os&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;orderSuccessResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;3&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Profile service returns a successful response on time, but order service returns an error.
&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;timeout&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;2&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="n"&gt;ps&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;profileSuccessResponse&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="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;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewMockService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;errorOrderResponse&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="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Other combinations...&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementing The Aggregator
&lt;/h3&gt;

&lt;p&gt;The goal of the aggregator is to call those two services concurrently, and stop as soon as one of the queries fail.&lt;br&gt;
You must use &lt;code&gt;golang.org/x/sync/errgroup&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First let's define the &lt;code&gt;Aggregator&lt;/code&gt;, we need the two services and a timeout:&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;UserAggregator&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;profileService&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;
    &lt;span class="n"&gt;ordersService&lt;/span&gt;  &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The go-kata also mentions that the &lt;code&gt;Aggregator&lt;/code&gt; needs to be configurable using the &lt;strong&gt;Functional Options Pattern&lt;/strong&gt;, so then we can define the &lt;em&gt;constructor&lt;/em&gt; 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;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ps&lt;/span&gt; &lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Service&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserAggregator&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;UserAggregator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ua&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;UserAggregator&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;profileService&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ps&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ordersService&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;,&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;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;option&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;options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;And then, finally the actual &lt;code&gt;Aggregate&lt;/code&gt; implementation. We need to declare a &lt;code&gt;context.Context&lt;/code&gt; using the timeout passed as a struct field, and then use:&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;g&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;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithContext&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;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To concurrently query the two services.&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;ua&lt;/span&gt; &lt;span class="n"&gt;UserAggregator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Aggregate&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;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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;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="n"&gt;ua&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timeout&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;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;user&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt;
        &lt;span class="n"&gt;orderValue&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;g&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;errgroup&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithContext&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;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&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="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;profileService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetProfile&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;u&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&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="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Go&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="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;ua&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ordersService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetOrder&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;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;orderValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;o&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Order&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="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;""&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="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"User: %s | Orders: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderValue&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;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;I'm working through more go-kata problems and publishing solutions in my fork. &lt;br&gt;
I'd love to hear your feedback:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Would you solve this differently?&lt;/li&gt;
&lt;li&gt;Are there edge cases I'm missing?&lt;/li&gt;
&lt;li&gt;What Go patterns would you apply?&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>programming</category>
      <category>learning</category>
    </item>
    <item>
      <title>Elegant Domain-Driven Design objects in Go</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Mon, 19 Jan 2026 05:41:09 +0000</pubDate>
      <link>https://dev.to/manuelarte/elegant-domain-driven-design-objects-in-go-2bhi</link>
      <guid>https://dev.to/manuelarte/elegant-domain-driven-design-objects-in-go-2bhi</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;❓How do you define in Go your domain objects?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go isn't your typical object-oriented language. When you try to implement Domain-Driven Design (DDD) concepts like &lt;code&gt;Entities&lt;/code&gt; and &lt;code&gt;Value Objects&lt;/code&gt; it can feel that you are fighting against the language.&lt;/p&gt;

&lt;p&gt;In this article, I'll share practical patterns I've used to implement DDD concepts in Go. We'll focus on making your domain code expressive, type-safe, and maintainable.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️This is an opinionated article that hopefully helps you to implement better and more elegant structs.&lt;br&gt;
&lt;em&gt;Aggregates are left out on purpose.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Our Domain: Coffee Shop Loyalty Program
&lt;/h2&gt;

&lt;p&gt;Let's come up with an easy example so we can focus on how to properly define DDD structs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem Space
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"How do we encourage customers to return to our coffee shop by rewarding repeat purchases?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Core Problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customers buy coffee.&lt;/li&gt;
&lt;li&gt;We want to give them points for each purchase.&lt;/li&gt;
&lt;li&gt;Points expire after 30 days.&lt;/li&gt;
&lt;li&gt;We can show a leaderboard and give rewards like free coffee.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Solution Space
&lt;/h3&gt;

&lt;p&gt;After several collaborations/iterations with the domain experts, we've identified:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An entity &lt;code&gt;Customer&lt;/code&gt;, that contains customer's info and their coffee orders.&lt;/li&gt;
&lt;li&gt;A value object &lt;code&gt;CoffeeOrder&lt;/code&gt;, that contains information about the order.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Let's start implementing the &lt;code&gt;CoffeeOrder&lt;/code&gt; first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial Implementation Attempt
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Value Objects
&lt;/h3&gt;

&lt;p&gt;Value objects are immutable objects representing descriptive aspects of a domain, defined solely by its attributes (values) rather than a unique identity.&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;CoffeeOrder&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// Size of the ordered coffee.&lt;/span&gt;
  &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="c"&gt;// OrderBy user id that ordered the coffee.&lt;/span&gt;
  &lt;span class="n"&gt;OrderBy&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="c"&gt;// OrderTime time when the ordered happened.&lt;/span&gt;
  &lt;span class="n"&gt;OrderTime&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, there is not anything like &lt;code&gt;ID&lt;/code&gt;, or &lt;code&gt;CoffeeOrderID&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Entities
&lt;/h3&gt;

&lt;p&gt;Entities are objects defined by their unique identity, not just its attributes, possessing a lifecycle and continuity through changes in its state.&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;Customer&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// ID of the customer.&lt;/span&gt;
  &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="c"&gt;// Name of the customer.&lt;/span&gt;
  &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="c"&gt;// CoffeeOrders the coffee orders of this customer.&lt;/span&gt;
  &lt;span class="n"&gt;CoffeeOrders&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;CoffeeOrder&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we can implement the business logic by asking the &lt;code&gt;Customer's&lt;/code&gt; for their points at a particular moment in time, with 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;// PointsAt returns the points of a customer at a moment in time.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;PointsAt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&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="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;co&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;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CoffeeOrders&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;points&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;co&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&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;points&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Despite this can look OK, there are many things that can be improved.&lt;/p&gt;

&lt;h2&gt;
  
  
  Levelling Up: Making Our Domain More Robust
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Immutability
&lt;/h3&gt;

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

&lt;p&gt;An entity needs to mutate, but a value object needs to be immutable. The current implementation does not guarantee immutability for the &lt;code&gt;CoffeeOrder&lt;/code&gt; struct. &lt;br&gt;
In fact, this is a concept that it's not natural in Go, and here is an example in which we need to fight against the language.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❓How To Achieve Immutability&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;One of the most obvious things to do is to use non-pointer receivers in the struct's methods, but fields can't be exported either, because if not, they can be modified like so:&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;co&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because field can't be exported, then we need to add a &lt;em&gt;constructor&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎓 There are no constructor in Go, but people call constructors to functions that starts with &lt;code&gt;New&lt;/code&gt;, or &lt;code&gt;Must&lt;/code&gt; and returns either the struct, or the struct and an error.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So we can have 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;type&lt;/span&gt; &lt;span class="n"&gt;CoffeeOrder&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// size of the ordered coffee.&lt;/span&gt;
  &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
  &lt;span class="c"&gt;// orderBy user id that ordered the coffee.&lt;/span&gt;
  &lt;span class="n"&gt;orderBy&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="c"&gt;// orderTime time when the ordered happened.&lt;/span&gt;
  &lt;span class="n"&gt;orderTime&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="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewCoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&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;orderBy&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderTime&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;CoffeeOrder&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;CoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;orderTime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;orderTime&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;In this case this is enough, but we need to make sure that each field is also immutable. As an example, a value object that uses a &lt;code&gt;slice&lt;/code&gt; or a &lt;code&gt;map&lt;/code&gt; as an input parameter, needs to make sure that that can't be modified externally (defensive copy).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❓ Is It Now Immutable and Completely Ready?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The answer is not, since the struct is exported, we could skip the instantiation of the struct using the constructor and directly do:&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;co&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;CoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creating a zero-value struct that is clearly invalid.&lt;br&gt;
To avoid that you could create an interface 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;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;CoffeeOrder&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;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;CoffeeSize&lt;/span&gt;
    &lt;span class="n"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt;
    &lt;span class="n"&gt;OrderTime&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;Time&lt;/span&gt;
    &lt;span class="n"&gt;Points&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ref&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;CoffeePoints&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// method to make sure interface implementation is only defined in this package.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;coffeeOrder&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// size of the ordered coffee.&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;CoffeeSize&lt;/span&gt;
    &lt;span class="c"&gt;// orderBy user id that ordered the coffee.&lt;/span&gt;
    &lt;span class="n"&gt;orderBy&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt;
    &lt;span class="c"&gt;// orderTime time when the ordered happened.&lt;/span&gt;
    &lt;span class="n"&gt;orderTime&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="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the constructor would instantiate &lt;code&gt;coffeeOrder&lt;/code&gt; but returns &lt;code&gt;CoffeeOrder&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Key concepts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interface hides implementation details.&lt;/li&gt;
&lt;li&gt;Constructor validates business rules.&lt;/li&gt;
&lt;li&gt;No exported fields prevent direct mutation.&lt;/li&gt;
&lt;li&gt;Value receivers (&lt;code&gt;CoffeeOrder&lt;/code&gt;, not &lt;code&gt;coffeeOrder&lt;/code&gt;) prevent modification.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Domain-Specific Types, Not Primitives
&lt;/h3&gt;

&lt;p&gt;Go has the option to create custom types with &lt;a href="https://go.dev/ref/spec#Type_definitions" rel="noopener noreferrer"&gt;Type Definition&lt;/a&gt;, this allows us to leverage the behaviour of primitive types to give more meaning to our fields.&lt;/p&gt;

&lt;p&gt;As an example, we could define a type 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;type&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it in both our structs, giving more meaning to the field. This custom type allows us to define functions that accept a &lt;code&gt;CustomerID&lt;/code&gt; not just a regular int.&lt;/p&gt;

&lt;p&gt;And the same goes with the coffee size, allowing us to add new methods to this new type like validating the value.&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;CoffeeSize&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;

&lt;span class="c"&gt;// IsValid returns whether the coffee size has a valid value or not.&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;cs&lt;/span&gt; &lt;span class="n"&gt;CoffeeSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;IsValid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;cs&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;"small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"medium"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"large"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;💡In general, I recommend to define new types over primitive types, since they give more domain meaning to your struct definitions and function/methods. And allows you to create custom methods that enhance their functionality in a localized way.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Creating Rich Domain Errors
&lt;/h3&gt;

&lt;p&gt;Now, we can change our &lt;code&gt;CoffeeOrder&lt;/code&gt; constructor 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;NewCoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="n"&gt;CoffeeSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderBy&lt;/span&gt; &lt;span class="n"&gt;CustomerID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;orderTime&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="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CoffeeOrder&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="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&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;CoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid Coffee Size"&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;coffeeOrder&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;      &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;orderBy&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;orderBy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;orderTime&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;orderTime&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are checking whether the value given by the user is a correct coffee size or not, and if not we return an error.&lt;/p&gt;

&lt;p&gt;In this case we are creating an error directly, but the error itself does not contain any meaning, just a string with the error message.&lt;/p&gt;

&lt;p&gt;I also recommend creating custom errors that give enough context to the caller to understand what happened.&lt;br&gt;
We could create 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;var&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WrongCoffeeSizeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;WrongCoffeeSizeError&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;Size&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;WrongCoffeeSizeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Error&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;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invalid coffee size: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, return it 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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IsValid&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;CoffeeOrder&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;WrongCoffeeSizeError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Size&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;size&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;
  
  
  Service Layer
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Services&lt;/code&gt; are used in DDD to orchestrate business operations that are above the domain. In this case, we could create a service to get all the &lt;code&gt;CoffeeOrder&lt;/code&gt;s in the last 30 days, then get all the &lt;code&gt;Customer's&lt;/code&gt; of those orders and sort them by points to get the leaderboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Linting
&lt;/h3&gt;

&lt;p&gt;Some of these practices can be enforced with a linter. There are many linters available in Go, but not one specialized for DDD, so I decided to create one that I use in my projects to make sure that I check patterns like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immutability for &lt;code&gt;Value objects&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Custom types over primitives for &lt;code&gt;Entities&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Pointer and non-pointer receivers for &lt;code&gt;Entities&lt;/code&gt; and &lt;code&gt;Value objects&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;No &lt;code&gt;errors.New&lt;/code&gt; used in returning a method call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's still under heavy development, but hopefully it can help you to create more elegant objects.&lt;br&gt;
Here is the link to the repository &lt;a href="https://github.com/manuelarte/godddlint" rel="noopener noreferrer"&gt;godddlint&lt;/a&gt; in case you are interested.&lt;/p&gt;

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

&lt;p&gt;In this article we covered several DDD concepts but also other concepts like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Immutability.&lt;/li&gt;
&lt;li&gt;Create domain-specific types for compile-time safety.&lt;/li&gt;
&lt;li&gt;Defining new domain errors.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What patterns have you found effective for DDD in Go? Share your experiences in the comments! &lt;/p&gt;

</description>
      <category>ddd</category>
      <category>go</category>
      <category>entity</category>
      <category>valueobjects</category>
    </item>
    <item>
      <title>Pagination in GORM</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Mon, 23 Jun 2025 20:58:51 +0000</pubDate>
      <link>https://dev.to/manuelarte/pagination-in-gorm-13i</link>
      <guid>https://dev.to/manuelarte/pagination-in-gorm-13i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://gorm.io/index.html" rel="noopener noreferrer"&gt;Gorm&lt;/a&gt; is the most used ORM package in Go, but, despite that, it is lacking some “basic” functionality.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of those lacking features is Pagination.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Pagination is an essential feature for managing large datasets in web applications. It is an approach to limit and display part of the total data in a database, so then not all the table needs to be retrieved in one “go”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While GORM provides documentation on how to use pagination using &lt;a href="https://gorm.io/docs/scopes.html" rel="noopener noreferrer"&gt;scopes&lt;/a&gt;, it leaves room for improvement in flexibility and usability. &lt;/p&gt;

&lt;p&gt;Here, I am going to explain an alternative to scopes for pagination, using GORM’s &lt;a href="https://gorm.io/gen/clause.html" rel="noopener noreferrer"&gt;Clauses&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pagination Using Scopes
&lt;/h2&gt;

&lt;p&gt;GORM’s documentation introduces Scopes as a way to re-use common code. In the documentation example, we can see that they define a pagination scope function similar to 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;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="kt"&gt;int&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;db&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&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="k"&gt;return&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;gorm&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="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&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="c"&gt;// validate page and pageSize&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="n"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;pageSize&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;Offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageSize&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;page&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;pageSize&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;10&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;Scopes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pageSize&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Find&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;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, in order to apply pagination, we need to use the code &lt;/p&gt;

&lt;p&gt;&lt;code&gt;db.Scopes(Paginate(page, pageSize))…&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pagination Using Clauses
&lt;/h2&gt;

&lt;p&gt;A different and, arguably, more elegant approach is to use GORM Clauses, this approach is a bit different to using Scopes, since Clauses are on charge of modifying the database queries, in particular, the &lt;code&gt;WHERE&lt;/code&gt; clause.&lt;/p&gt;

&lt;p&gt;Let’s start by defining the pagination struct&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;Pagination&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;page&lt;/span&gt;          &lt;span class="kt"&gt;int&lt;/span&gt;
 &lt;span class="n"&gt;pageSize&lt;/span&gt;      &lt;span class="kt"&gt;int&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;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetPage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&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;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;GetPageSize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;int&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;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pageSize&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, let’s implement the two interfaces needed to use this struct in a GORM clause 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="n"&gt;clause&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Expression&lt;/span&gt;
&lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatementModifier&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the struct 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;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ModifyStatement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stm&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gorm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// We modify statement to add the pagination&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;stm&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DB&lt;/span&gt;
  &lt;span class="n"&gt;stm&lt;/span&gt;&lt;span class="o"&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;Limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Offset&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pageSize&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;p&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c"&gt;// The Build method is left empty since pagination does not require any additional SQL clauses.&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can use pagination as follows:&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;pagination&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;Pagination&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="o"&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;pageSize&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&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;Clauses&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;pagination&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Find&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;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;To make this approach reusable and enhance its capabilities, I developed &lt;a href="https://github.com/manuelarte/pagorminator" rel="noopener noreferrer"&gt;PaGorminator&lt;/a&gt; — a library that uses this feature for pagination, while adding other features like unpaged requests and automatic metadata population like &lt;strong&gt;total number of pages, and total count&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To use it, do as follows:&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;// Add plugin&lt;/span&gt;
&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&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;Use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pagorminator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaGorminator&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;pageRequest&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;pagorminator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageRequest&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;10&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;Clauses&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Find&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;users&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;// this will apply pagination, and also populate pageRequest with:&lt;/span&gt;
&lt;span class="c"&gt;// - the total number of pages&lt;/span&gt;
&lt;span class="c"&gt;// - total count&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>go</category>
      <category>pagination</category>
      <category>gorm</category>
    </item>
    <item>
      <title>Introducing GitHub Kudos</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Thu, 23 Jan 2025 20:57:09 +0000</pubDate>
      <link>https://dev.to/manuelarte/introducing-github-kudos-k83</link>
      <guid>https://dev.to/manuelarte/introducing-github-kudos-k83</guid>
      <description>&lt;p&gt;The open-source community is built on collaboration, recognition, and support. If you are familiar with platforms like &lt;a href="https://github.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, you know how challenging it can be to express who you think they are talented developers. &lt;br&gt;
We all, also, know how much a word of encouragement can mean to someone who has worked tirelessly on their code or projects.&lt;/p&gt;

&lt;p&gt;That’s why I created &lt;em&gt;GitHub Kudos&lt;/em&gt;, a simple way to give shoutouts and kudos to other GitHub users.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is GitHub Kudos
&lt;/h2&gt;

&lt;p&gt;GitHub Kudos is an app that allows you to generate images with the recommendation for GitHub users. These images feature the user’s profile avatar and a recommendation message written by you. They can be used in GitHub profiles, personal websites, blogs, or anywhere you want either show who you recommend, or who is recommending you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does It Work
&lt;/h2&gt;

&lt;p&gt;It’s very simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a repository in your GitHub account called &lt;code&gt;github-kudos&lt;/code&gt;. (e.g., &lt;code&gt;manuelarte/github-kudos&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Inside this repository, create a file named after the GitHub username of the person you want to recommend (e.g., &lt;code&gt;octocat.md&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Write your recommendation in plain text inside the file.&lt;/li&gt;
&lt;li&gt;After you push the file, the image can be visualized at &lt;code&gt;https://github.com/{{your-github-username}}/kudos/{{other-github-username}}&lt;/code&gt;. (e.g. &lt;code&gt;https://github-kudos.com/manuelarte/kudos/octocat&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;I created a GitHub template that you can use as reference at &lt;code&gt;https://github.com/manuelarte/github-kudos-template/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once people recommend you, you have a ready-to-use image to share on your GitHub profile, website, or social media!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Did I Build This
&lt;/h2&gt;

&lt;p&gt;I’ve always believed in the power of recognition. As developers, we often rely on each other’s work, whether it’s an open-source library, a piece of advice, or a helpful comment in an issue. However, we rarely take a moment to publicly acknowledge those contributions. GitHub Kudos aims to change that by making it easy to celebrate others’ efforts.&lt;/p&gt;

&lt;p&gt;I also believe that a GitHub profile, in which you showcase your projects, plus you show how people see feel when working with you, can help in the always tedious process of looking for a new job.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Personalized Recommendations: You decide what to write about someone, making each image unique and meaningful, with the possibility of changing it at any time.&lt;/li&gt;
&lt;li&gt;Visual Appeal: The images are designed to stand out, making them perfect for GitHub READMEs or social media.&lt;/li&gt;
&lt;li&gt;Open and free: Anyone can create a github-kudos repository and start giving kudos to others.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Join The Kudos Movement
&lt;/h2&gt;

&lt;p&gt;Not only does it build a more supportive community, but it also encourages people to continue creating, sharing, and collaborating.&lt;/p&gt;

&lt;p&gt;If this resonates with you, give GitHub Kudos a try and start spreading positivity today.&lt;/p&gt;

&lt;p&gt;If you want to see how it looks, check my profile: &lt;code&gt;https://github.com/manuelarte#-people-i-recommend.&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I’d love to hear your thoughts, feedback, or ideas to improve GitHub Kudos.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>github</category>
      <category>kudos</category>
      <category>recommendation</category>
    </item>
    <item>
      <title>Simplify Your REST API Responses with Milogo for Gin-Gonic</title>
      <dc:creator>Manuel Doncel Martos</dc:creator>
      <pubDate>Mon, 18 Nov 2024 16:54:24 +0000</pubDate>
      <link>https://dev.to/manuelarte/simplify-your-rest-api-responses-with-milogo-for-gin-gonic-4a9h</link>
      <guid>https://dev.to/manuelarte/simplify-your-rest-api-responses-with-milogo-for-gin-gonic-4a9h</guid>
      <description>&lt;p&gt;&lt;em&gt;Gin-Gonic Middleware that implements fields selection pattern&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;At my company we use Go to build internal tools. Recently I worked in a REST API using &lt;a href="https://gin-gonic.com/" rel="noopener noreferrer"&gt;gin-gonic&lt;/a&gt;, that required displaying a lot of data across many endpoints.&lt;/p&gt;

&lt;p&gt;One must have feature in this type of scenario, is &lt;strong&gt;pagination&lt;/strong&gt;, but and often overlooked pattern is &lt;strong&gt;partial response (a.k.a field selection)&lt;/strong&gt;. Which is also a very nice addition to filter out the amount of data in the responses of your web server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s field selection?
&lt;/h2&gt;

&lt;p&gt;Let us first make it clear what I mean with a field selection. Imagine that you have the following endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/products&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"createdAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-18-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"updatedAt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2024-18-11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"manufacturedBy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"myshop"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stock"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;552&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using partial responses, clients can filter the output with a fields query parameter, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/api/products?fields=code,price&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"currency"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EUR"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Only&lt;/strong&gt; the fields declared in the query parameter are returned. Reducing the payload size and saving bandwidth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Milogo
&lt;/h2&gt;

&lt;p&gt;I could not find any implementation available for this pattern, so I decided to create it myself, and that is how &lt;a href="https://github.com/manuelarte/milogo" rel="noopener noreferrer"&gt;Milogo&lt;/a&gt; was born. &lt;br&gt;
Milogo is a Gin middleware that processes API responses, filters out fields specified in the fields query parameter, and return only the requested data.&lt;/p&gt;

&lt;p&gt;Some of the main features available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/manuelarte/milogo/tree/main/examples/simpleArray" rel="noopener noreferrer"&gt;Support for json objects and json arrays.&lt;/a&gt;&lt;br&gt;
So Milogo can filter fields for JSON responses that starts with an array of items or just with one single item.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/manuelarte/milogo/tree/main/examples/nested" rel="noopener noreferrer"&gt;Support for filtering out fields in nested json objects.&lt;/a&gt;&lt;br&gt;
Milogo also supports filtering nested JSON objects with the following format e.g. code,price(amount)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/manuelarte/milogo/tree/main/examples/wrapped" rel="noopener noreferrer"&gt;Support for json wrapped in another json.&lt;/a&gt;&lt;br&gt;
Sometimes the JSON responses are wrapped in another JSON object, Milogo support filtering the actual payload (see example wrapped):&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;GET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;/products?fields=code,price(amount)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"price"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"amount"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"_metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;As any gin middleware, Milogo is really easy to use and setup, you can follow the README in the github repository, but basically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;r := gin.Default()
r.Use(Milogo())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is enough to add Milogo middleware to your api.&lt;/p&gt;

&lt;p&gt;In the previous example Milogo is applied to every single endpoint, but it is also possible to apply only to a group of endpoints, or just to an specific endpoint, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;group := r.Group("/products", milogo.Milogo())
group.GET("", productsHandler)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the previous example, only the &lt;em&gt;/products&lt;/em&gt; group would have the Milogo’s middleware applied.&lt;/p&gt;

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

&lt;p&gt;Milogo is designed to simplify REST API development and improve client-server interactions. Check out the &lt;a href="https://github.com/manuelarte/milogo" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; for examples and documentation.&lt;/p&gt;

&lt;p&gt;Feel free to reach out or contribute — let’s make REST APIs efficient together!&lt;/p&gt;

</description>
      <category>go</category>
      <category>gingonic</category>
      <category>restapi</category>
    </item>
  </channel>
</rss>
