<?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>The Ops Community ⚙️: Kevin Wan</title>
    <description>The latest articles on The Ops Community ⚙️ by Kevin Wan (@kevwan).</description>
    <link>https://community.ops.io/kevwan</link>
    <image>
      <url>https://community.ops.io/images/HvRiZdx8zYkCI24CQhUGLXbobJbz_yGT6rKTUZwErWQ/rs:fill:90:90/g:sm/mb:500000/ar:1/aHR0cHM6Ly9jb21t/dW5pdHkub3BzLmlv/L3JlbW90ZWltYWdl/cy91cGxvYWRzL3Vz/ZXIvcHJvZmlsZV9p/bWFnZS8xNzYvOWMy/Y2JhNjMtOGVlNi00/NzQzLTk0ZWItNmM5/ZDhmY2MyNTc5Lmpw/ZWc</url>
      <title>The Ops Community ⚙️: Kevin Wan</title>
      <link>https://community.ops.io/kevwan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://community.ops.io/feed/kevwan"/>
    <language>en</language>
    <item>
      <title>Implementing service discovery for microservices</title>
      <dc:creator>Kevin Wan</dc:creator>
      <pubDate>Tue, 28 Jun 2022 04:21:23 +0000</pubDate>
      <link>https://community.ops.io/kevwan/implementing-service-discovery-for-microservices-5bcb</link>
      <guid>https://community.ops.io/kevwan/implementing-service-discovery-for-microservices-5bcb</guid>
      <description>&lt;h2&gt;
  
  
  What is service registration discovery?
&lt;/h2&gt;

&lt;p&gt;For developers who work with microservices, the concepts of service discovery should be familiar.&lt;/p&gt;

&lt;p&gt;For example, if service A depends on service B, we need to tell service A where to invoke service B. This is the problem that service discovery has to solve.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/Qym8a4aRnvh5YXQpRA_80hYILHlE3XtPUjYHrq3lMMQ/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWVmMzQ0YzBlNTE1/NDVjZGUxYjJlZmY3/NTY1Y2UyYmJiYzM4/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/Qym8a4aRnvh5YXQpRA_80hYILHlE3XtPUjYHrq3lMMQ/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWVmMzQ0YzBlNTE1/NDVjZGUxYjJlZmY3/NTY1Y2UyYmJiYzM4/LnBuZw" alt="service discovery" width="880" height="608"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Service B&lt;/code&gt; registers itself to the &lt;code&gt;Service Registry&lt;/code&gt; called &lt;strong&gt;Service Registration&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service A&lt;/code&gt; discovering node information of &lt;code&gt;Service B&lt;/code&gt; from &lt;code&gt;Service Registry&lt;/code&gt; is called &lt;strong&gt;Service Discovery&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Service Registration
&lt;/h2&gt;

&lt;p&gt;Service registration is for the server side and is required after the service is started and is divided into several parts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Startup registration&lt;/li&gt;
&lt;li&gt;Timed Renewal&lt;/li&gt;
&lt;li&gt;Withdrawal&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Startup Registration
&lt;/h3&gt;

&lt;p&gt;When a service node is up, it needs to register itself to the &lt;code&gt;Service Registry&lt;/code&gt; so that other nodes can easily discover itself. The registration needs to be done when the service is up and ready to accept requests, and a validity period will be set to prevent the process from being accessed even after an abnormal exit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timed Renewal
&lt;/h3&gt;

&lt;p&gt;The equivalent of &lt;code&gt;keep alive&lt;/code&gt; is to periodically tell &lt;code&gt;Service Registry&lt;/code&gt; that it is still alive and can continue to serve.&lt;/p&gt;

&lt;h3&gt;
  
  
  Withdrawal
&lt;/h3&gt;

&lt;p&gt;When a process exits, we should actively revoke the registration information so that the caller can distribute the request to another node in time. At the same time, go-zero ensures that even if a node exits without active deregistration, the node can be taken off in time by adaptive load balancing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Service Discovery
&lt;/h2&gt;

&lt;p&gt;Service discovery is for the caller side and is generally divided into two types of problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Inventory fetch&lt;/li&gt;
&lt;li&gt;Incremental watch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is also a common engineering problem of&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coping with service discovery failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When a service discovery service (such as etcd, consul, nacos, etc.) goes down, we don't modify the list of endpoints we've already fetched, so we can better ensure that the services we depend on can still interact properly after etcd, etc. goes down.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inventory fetch
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/zhbEU28WnBolER2iGtZG-5ODKeuqydYQh-Lsyol8I_E/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTM2NTZmMGQ2ZjUz/MDIyZDUwYWY3ODAx/OWQ2NmE1NDIwNDI3/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/zhbEU28WnBolER2iGtZG-5ODKeuqydYQh-Lsyol8I_E/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTM2NTZmMGQ2ZjUz/MDIyZDUwYWY3ODAx/OWQ2NmE1NDIwNDI3/LnBuZw" alt="Inventory fetch" width="880" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;Service A&lt;/code&gt; starts, it needs to get the list of existing nodes of &lt;code&gt;Service B&lt;/code&gt; from &lt;code&gt;Service Registry&lt;/code&gt;: &lt;code&gt;Service B1&lt;/code&gt;, &lt;code&gt;Service B2&lt;/code&gt;, &lt;code&gt;Service B3&lt;/code&gt;, and then select the appropriate nodes to send requests based on its own load balancing algorithm.&lt;/p&gt;

&lt;h3&gt;
  
  
  Incremental watch
&lt;/h3&gt;

&lt;p&gt;The above diagram already has &lt;code&gt;Service B1&lt;/code&gt;, &lt;code&gt;Service B2&lt;/code&gt;, &lt;code&gt;Service B3&lt;/code&gt;, if &lt;code&gt;Service B4&lt;/code&gt; is started, then we need to notify &lt;code&gt;Service A&lt;/code&gt; that there is an additional node. As shown in the figure.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/-BaOlvWA71JQtK9zHiYVQnOlYcl8E4E21ji4Tc0zq0c/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTEwM2MxNGYwMGZm/MDcyMzI3NDVlMmI1/MTJjY2ExZDJmZDM4/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/-BaOlvWA71JQtK9zHiYVQnOlYcl8E4E21ji4Tc0zq0c/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTEwM2MxNGYwMGZm/MDcyMzI3NDVlMmI1/MTJjY2ExZDJmZDM4/LnBuZw" alt="Incremental watch" width="880" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Service discovery failures
&lt;/h3&gt;

&lt;p&gt;For service callers, we all cache a list of available nodes in memory. Whether we use &lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;consul&lt;/code&gt; or &lt;code&gt;nacos&lt;/code&gt;, we may face a service discovery cluster failure, take &lt;code&gt;etcd&lt;/code&gt; as an example, when we encounter &lt;code&gt;etcd&lt;/code&gt; failure, we need to freeze the node information of &lt;code&gt;Service B&lt;/code&gt; without changing it, we must not empty the node information at this time, once it is empty, we can't get it, while the nodes of &lt;code&gt;Service B&lt;/code&gt; nodes are probably normal, and &lt;code&gt;go-zero&lt;/code&gt; will automatically isolate and restore the failed node.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/UgdDq-mNqOTfBc-pU_BG-3Cy9Xi87ZYieDfdxcTvEEc/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWQ2ZDE3MjAxODdh/ZjY5MTQwZDBlNDJh/ZGU3ODk4NmI4ZWEx/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/UgdDq-mNqOTfBc-pU_BG-3Cy9Xi87ZYieDfdxcTvEEc/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWQ2ZDE3MjAxODdh/ZjY5MTQwZDBlNDJh/ZGU3ODk4NmI4ZWEx/LnBuZw" alt="discovery failures" width="880" height="621"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the basic principle of service registration and service discovery, but of course it is still complicated to implement, so let's take a look at what service discovery methods are supported in &lt;code&gt;go-zero&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  go-zero's built-in service discovery
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;go-zero&lt;/code&gt; supports three service discovery methods by default.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;direct connection&lt;/li&gt;
&lt;li&gt;direct connection * etcd-based service discovery&lt;/li&gt;
&lt;li&gt;kubernetes endpoints-based service discovery&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Direct connection
&lt;/h3&gt;

&lt;p&gt;Direct connection is the simplest way, when our service is simple enough, such as a single machine can host our business, we can just use this way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/8RsY7Qom6MAjdUK-dQ5-nRDamsPf0mSQ-ZxbFqJm-wk/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWUxYmYxYWMzZmJj/Y2NlODIzZjNkMWZm/ODEwNGUzZmVmM2Qx/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/8RsY7Qom6MAjdUK-dQ5-nRDamsPf0mSQ-ZxbFqJm-wk/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWUxYmYxYWMzZmJj/Y2NlODIzZjNkMWZm/ODEwNGUzZmVmM2Qx/LnBuZw" alt="Direct connection" width="880" height="505"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify &lt;code&gt;endpoints&lt;/code&gt; directly in the &lt;code&gt;rpc&lt;/code&gt; configuration file, e.g.&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;Rpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Endpoints&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.111:3456&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.112:3456&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;zrpc&lt;/code&gt; caller will allocate the load to these two nodes, one of the nodes has a problem &lt;code&gt;zrpc&lt;/code&gt; will automatically take off, and when the node is restored will again allocate the load.&lt;/p&gt;

&lt;p&gt;The disadvantage of this approach is that the nodes cannot be added dynamically, and each new node requires a change in the caller's configuration and a restart.&lt;/p&gt;

&lt;h3&gt;
  
  
  etcd-based service discovery
&lt;/h3&gt;

&lt;p&gt;Once our service has a certain size, because a service may be dependent on many services, we need to be able to dynamically add and remove nodes without having to modify many caller configurations and restarts.&lt;/p&gt;

&lt;p&gt;Common service discovery solutions are &lt;code&gt;etcd&lt;/code&gt;, &lt;code&gt;consul&lt;/code&gt;, &lt;code&gt;nacos&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/D4vZ6PHadvRIM37eUNyBmmIAQG37WQqujK1ZLXGfFKs/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTJlYTg2ZDA1NDc0/ZDk4ZjQ1NTM4MzM0/ZjA4OTQ1ZTMxNWI0/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/D4vZ6PHadvRIM37eUNyBmmIAQG37WQqujK1ZLXGfFKs/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTJlYTg2ZDA1NDc0/ZDk4ZjQ1NTM4MzM0/ZjA4OTQ1ZTMxNWI0/LnBuZw" alt="etcd-based service discovery" width="880" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;go-zero has a built-in &lt;code&gt;etcd&lt;/code&gt;-based service discovery scheme, which is used as follows.&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;Rpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Etcd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="na"&gt;Hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.111:2379&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.112:2379&lt;/span&gt;
     &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;192.168.0.113:2379&lt;/span&gt;
     &lt;span class="na"&gt;Key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;user.rpc&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Hosts&lt;/code&gt; is the &lt;code&gt;etcd&lt;/code&gt; cluster address&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Key&lt;/code&gt; is the &lt;code&gt;key&lt;/code&gt; on which the service is registered&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service discovery based on Kubernetes Endpoints
&lt;/h3&gt;

&lt;p&gt;If our services are deployed on a &lt;code&gt;Kubernetes&lt;/code&gt; cluster, &lt;code&gt;Kubernetes&lt;/code&gt; itself manages the cluster state through its own &lt;code&gt;etcd&lt;/code&gt;, and all services register their node information to &lt;code&gt;Endpoints&lt;/code&gt; objects, so we can directly give &lt;code&gt;deployment&lt;/code&gt; permissions to read the cluster's &lt;code&gt;Endpoints&lt;/code&gt; object to get the node information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/rOgDxLrxvDcJ79-Xfm1U2NsN8D6S8QDoKp4yyLQFLUY/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTE1Yzc3ZWRiNzk3/Mzk5OGJiNjMyNTE0/YmFkYTVhMmUzNzVj/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/rOgDxLrxvDcJ79-Xfm1U2NsN8D6S8QDoKp4yyLQFLUY/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTE1Yzc3ZWRiNzk3/Mzk5OGJiNjMyNTE0/YmFkYTVhMmUzNzVj/LnBuZw" alt="Kubernetes Endpoints" width="880" height="757"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each &lt;code&gt;Pod&lt;/code&gt; of &lt;code&gt;Service B&lt;/code&gt; will register itself to the &lt;code&gt;Endpoints&lt;/code&gt; of the cluster when it starts&lt;/li&gt;
&lt;li&gt;When each &lt;code&gt;Pod&lt;/code&gt; of &lt;code&gt;Service A&lt;/code&gt; starts, it can get the node information of &lt;code&gt;Service B&lt;/code&gt; from the &lt;code&gt;Endpoints&lt;/code&gt; of the cluster&lt;/li&gt;
&lt;li&gt;When the node of &lt;code&gt;Service B&lt;/code&gt; changes, &lt;code&gt;Service A&lt;/code&gt; can sense it through &lt;code&gt;Endpoints&lt;/code&gt; of the &lt;code&gt;watch&lt;/code&gt; cluster&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Before this mechanism can work, we need to configure the &lt;code&gt;pod&lt;/code&gt; in the current &lt;code&gt;namespace&lt;/code&gt; to have access to the cluster &lt;code&gt;Endpoints&lt;/code&gt;, where there are three concepts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ClusterRole

&lt;ul&gt;
&lt;li&gt;ClusterRole defines a cluster-wide permission role that is not controlled by &lt;code&gt;namespace&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;ServiceAccount

&lt;ul&gt;
&lt;li&gt;Defines the &lt;code&gt;service account&lt;/code&gt; within the &lt;code&gt;namespace&lt;/code&gt; scope&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;ClusterRoleBinding

&lt;ul&gt;
&lt;li&gt;Bind a defined &lt;code&gt;ClusterRole&lt;/code&gt; to a &lt;code&gt;ServiceAccount&lt;/code&gt; in a different &lt;code&gt;namespace&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


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

&lt;p&gt;The specific &lt;code&gt;Kubernetes&lt;/code&gt; configuration file can be found &lt;a href="https://github.com/tal-tech/go-zero/tree/master/zrpc/internal/resolver/kube/deploy"&gt;here&lt;/a&gt;, where &lt;code&gt;namespace&lt;/code&gt; is modified as needed.&lt;/p&gt;

&lt;p&gt;Note: Remember to check if these configurations are in place when you start up and don't have access to &lt;code&gt;Endpoints&lt;/code&gt; :)&lt;/p&gt;

&lt;p&gt;&lt;code&gt;zrpc&lt;/code&gt;'s &lt;code&gt;Kubernetes Endpoints&lt;/code&gt; based service discovery is used as follows.&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;Rpc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;Target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8s://mynamespace/myservice:3456&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mynamespace&lt;/code&gt;: the &lt;code&gt;namespace&lt;/code&gt; where the invoked &lt;code&gt;rpc&lt;/code&gt; service is located&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;myservice&lt;/code&gt;: the name of the invoked &lt;code&gt;rpc&lt;/code&gt; service&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;3456&lt;/code&gt;: the port of the called &lt;code&gt;rpc&lt;/code&gt; service&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Be sure to add &lt;code&gt;serviceAccountName&lt;/code&gt; to specify which &lt;code&gt;ServiceAccount&lt;/code&gt; to use when creating the &lt;code&gt;deployment&lt;/code&gt; configuration file, for example&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine-deployment&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;serviceAccountName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;endpoints-reader&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
        &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;sleep&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;infinity&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;serviceAccountName&lt;/code&gt; specifies which &lt;code&gt;ServiceAccount&lt;/code&gt; is used for the &lt;code&gt;pod&lt;/code&gt; created by the &lt;code&gt;deployment&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After both &lt;code&gt;server&lt;/code&gt; and &lt;code&gt;client&lt;/code&gt; are deployed to the &lt;code&gt;Kubernetes&lt;/code&gt; cluster, you can restart all &lt;code&gt;server&lt;/code&gt; nodes on a rolling basis with the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl rollout restart deploy &lt;span class="nt"&gt;-n&lt;/span&gt; adhoc server-deployment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the &lt;code&gt;client&lt;/code&gt; node log with the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl &lt;span class="nt"&gt;-n&lt;/span&gt; adhoc logs &lt;span class="nt"&gt;-f&lt;/span&gt; deploy/client-deployment &lt;span class="nt"&gt;--all-containers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can see that our service discovery mechanism follows the changes to the &lt;code&gt;server&lt;/code&gt; node perfectly, and there are no exception requests during service updates.&lt;/p&gt;

&lt;p&gt;The full code example is available at &lt;a href="https://github.com/zeromicro/zero-examples/tree/main/%20discovery/k8s"&gt;https://github.com/zeromicro/zero-examples/tree/main/discovery/k8s&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next article I will explain how to implement service registration discovery based on &lt;code&gt;consul&lt;/code&gt;, &lt;code&gt;nacos&lt;/code&gt;, etc. in &lt;code&gt;go-zero&lt;/code&gt;, so stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Project address
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/zeromicro/go-zero"&gt;https://github.com/zeromicro/go-zero&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to use &lt;code&gt;go-zero&lt;/code&gt; and &lt;strong&gt;star&lt;/strong&gt; to support us!&lt;/p&gt;

</description>
      <category>tutorials</category>
      <category>kubernetes</category>
      <category>github</category>
      <category>random</category>
    </item>
    <item>
      <title>Sending type-safe HTTP requests with Go</title>
      <dc:creator>Kevin Wan</dc:creator>
      <pubDate>Mon, 30 May 2022 15:47:26 +0000</pubDate>
      <link>https://community.ops.io/kevwan/sending-type-safe-http-requests-with-go-26dh</link>
      <guid>https://community.ops.io/kevwan/sending-type-safe-http-requests-with-go-26dh</guid>
      <description>&lt;h2&gt;
  
  
  Scenarios
&lt;/h2&gt;

&lt;p&gt;For Gophers, we basically write code for clients to request. Sometimes we need to request RESTful APIs provided by third parties. At this time, we feel that it's hard to assemble the requests, not difficult, but error-prone.&lt;/p&gt;

&lt;p&gt;For example, if we want to send a request like this, it looks very simple, but it's still tedious to actually write it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/articles/5/update?device=ios&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go-zero.dev&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer &amp;lt;jwt-token&amp;gt;&lt;/span&gt;

{"author": "kevin", "body": "this is not important!", "title": "my title", "type":6}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Go native way
&lt;/h2&gt;

&lt;p&gt;This API is actually quite simple and we can write it directly from scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
    &lt;span class="n"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewEncoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}{&lt;/span&gt;
        &lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;  &lt;span class="s"&gt;"my title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"body"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="s"&gt;"this is not important!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"kevin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;   &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;encoder&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&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="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&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;Stderr&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="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="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;"http://go-zero.dev/articles/%d/update?device=%s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ios"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;req&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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodPost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&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;Stderr&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="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Header&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Bearer &amp;lt;jwt-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;cli&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;cli&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&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;Stderr&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="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We ran a test and found that we didn't get &lt;code&gt;200 OK&lt;/code&gt;, dumped the packet and the request looks as follows. Can you think of the reason for the failure?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/articles/5/update?device=ios&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go-zero.dev&lt;/span&gt;
&lt;span class="na"&gt;User-Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Go-http-client/1.1&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;79&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer &amp;lt;jwt-token&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;Accept-Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gzip&lt;/span&gt;

{"author": "kevin", "body": "this is not important!", "title": "my title", "type":6}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The specific reasons for the failure will be discussed below, so let's explain this code first. You can see that the &lt;code&gt;map[string]interface{}&lt;/code&gt; is used for the splicing parameters, for each field we can't check if the type matches. Only when we send it out and receive &lt;code&gt;200 OK&lt;/code&gt; from the server, we can confirm that it is passed correctly. For example, the &lt;code&gt;type&lt;/code&gt; parameter is used here as &lt;code&gt;int&lt;/code&gt; type, we may write it as &lt;code&gt;string&lt;/code&gt; type by mistake. But it is still hard to find out that this parameter is written incorrectly without requesting it.&lt;/p&gt;

&lt;p&gt;So let's see how the &lt;code&gt;httpc&lt;/code&gt; package in &lt;code&gt;go-zero&lt;/code&gt; is used for type safety.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;httpc&lt;/code&gt; implementation
&lt;/h2&gt;

&lt;p&gt;Let's see how the code for requesting with the &lt;code&gt;httpc&lt;/code&gt; package is written.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http://go-zero.dev/articles/:id/update"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UpdateArticle&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;ID&lt;/span&gt;            &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`path: "id"`&lt;/span&gt;
    &lt;span class="n"&gt;Device&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`form: "device,options=ios,android,web,desktop"`&lt;/span&gt;
    &lt;span class="n"&gt;Authorization&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`header: "Authorization"`&lt;/span&gt;
    &lt;span class="n"&gt;Title&lt;/span&gt;         &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json: "title"`&lt;/span&gt;
    &lt;span class="n"&gt;Body&lt;/span&gt;          &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json: "body"`&lt;/span&gt;
    &lt;span class="n"&gt;Author&lt;/span&gt;        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json: "author"`&lt;/span&gt;
    &lt;span class="n"&gt;Type&lt;/span&gt;          &lt;span class="kt"&gt;int&lt;/span&gt;    &lt;span class="s"&gt;`json: "type"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;data&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;UpdateArticle&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;            &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Device&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"ios"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Bearer &amp;lt;jwt-token&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;         &lt;span class="s"&gt;"my title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="s"&gt;"this is not important!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;        &lt;span class="s"&gt;"kevin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;          &lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;httpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;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;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MethodPost&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintln&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;Stderr&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="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stdout&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's verify the code by sending a request, the result is as expected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/articles/5/update?device=ios&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;Host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go-zero.dev&lt;/span&gt;
&lt;span class="na"&gt;User-Agent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Go-http-client/1.1&lt;/span&gt;
&lt;span class="na"&gt;Content-Length&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;79&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json; charset=utf-8&lt;/span&gt;
&lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Bearer &amp;lt;jwt-token&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;Accept-Encoding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gzip&lt;/span&gt;

&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kevin"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"this is not important!"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;6&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;Did you find out that, in contrast to the previous one, there is one more header was set, &lt;code&gt;Content-Type: application/json; charset=utf-8&lt;/code&gt;, and we forgot to set &lt;code&gt;Content-Type&lt;/code&gt; in the previous code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;httpc&lt;/code&gt; implementation is very easy to understand by defining the type of the request and sending with &lt;code&gt;Do&lt;/code&gt;. With support for &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;form&lt;/code&gt;, &lt;code&gt;header&lt;/code&gt; and &lt;code&gt;json&lt;/code&gt; as shown in our code, it is very easy and type-safe to send &lt;code&gt;HTTP&lt;/code&gt; requests.&lt;/p&gt;

&lt;h2&gt;
  
  
  More Capabilities
&lt;/h2&gt;

&lt;p&gt;In addition to the ease of use and type-safety shown above, the &lt;code&gt;httpc&lt;/code&gt; package has the following features.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;timeout control with &lt;code&gt;context&lt;/code&gt;. You can pass &lt;code&gt;ctx&lt;/code&gt; for the requests.&lt;/li&gt;
&lt;li&gt;automatic integration of &lt;code&gt;OpenTelemetry&lt;/code&gt;. The &lt;code&gt;trace-id&lt;/code&gt;, &lt;code&gt;span-id&lt;/code&gt; returned by the server will be automatically written in the log, so that the client and server can work together to investigate the problems.&lt;/li&gt;
&lt;li&gt;use &lt;code&gt;httpc.Service&lt;/code&gt; to get the circuit breaker ability. When the server side has problems, it will automatically stop sending the requests, to avoid useless requests and reduce the pressure on the server side.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Project address
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/zeromicro/go-zero"&gt;https://github.com/zeromicro/go-zero&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to use &lt;code&gt;go-zero&lt;/code&gt; and &lt;strong&gt;star&lt;/strong&gt; to support us!&lt;/p&gt;

</description>
      <category>go</category>
      <category>devops</category>
      <category>tutorials</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Developing a RESTful API with Go</title>
      <dc:creator>Kevin Wan</dc:creator>
      <pubDate>Thu, 26 May 2022 04:46:53 +0000</pubDate>
      <link>https://community.ops.io/kevwan/developing-a-restful-api-with-go-h23</link>
      <guid>https://community.ops.io/kevwan/developing-a-restful-api-with-go-h23</guid>
      <description>&lt;h2&gt;
  
  
  When to use RESTful API
&lt;/h2&gt;

&lt;p&gt;For most startups, we should focus more on delivering the products in the early stage of business. The monolithic services have the advantages of simple architecture, easy deployment, and better development productivity, which can help us achieve the product requirements quickly. While we use monolithic services to deliver products quickly, we also need to reserve the possibility for business incresement, so we usually split different business modules clearly in monolithic services.&lt;/p&gt;

&lt;h2&gt;
  
  
  Shopping mall monolithic service architecture
&lt;/h2&gt;

&lt;p&gt;We take the mall as an example to build a monolithic service. The mall service is generally relatively complex and consists of multiple modules, the more important modules include account, product and order modules, etc. Each module will have its own independent business logic, and each module will also depend on some others. For example, the order module and the product module will depend on the account module. In the monolithic application this kind of dependency is usually accomplished by method calls between modules. Monolithic services generally share storage resources, such as &lt;code&gt;MySQL&lt;/code&gt; and &lt;code&gt;Redis&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The overall architecture of monolithic services is relatively simple, which is also the advantage of monolithic services. Customer requests are parsed through &lt;code&gt;DNS&lt;/code&gt; and forwarded to the mall's backend services through &lt;code&gt;Nginx&lt;/code&gt;. Mall services are deployed on cloud hosts. In order to achieve greater throughput and high availability, the service will generally deployed with multiple copies. This simple architecture can carry high throughput if well optimized. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/CmFjODtM20uuKHrzJGT2njR9W3uCxvKwftN7T_GOWf8/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTc5ODk2NzQ0MjRj/YzFkMzYwMGVjYzZm/M2ZmMDU2YmNhMzk5/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/CmFjODtM20uuKHrzJGT2njR9W3uCxvKwftN7T_GOWf8/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LTc5ODk2NzQ0MjRj/YzFkMzYwMGVjYzZm/M2ZmMDU2YmNhMzk5/LnBuZw" alt="" width="880" height="349"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, a request for order details interface &lt;code&gt;/order/detail&lt;/code&gt; is routed to the order module, which relies on the account module and the product module to compose the complete order details back to the user, and multiple modules in a single service generally share the database and cache.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.ops.io/images/T1QRmNq8nJZPi9aPy_kIMXx49NYRHhB-57oqaGpy2UE/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWQyMDhiMTE2NGQy/ZTAzMTQ5OTEzZjhk/MzEwZDhiNjk0NzEw/LnBuZw" class="article-body-image-wrapper"&gt;&lt;img src="https://community.ops.io/images/T1QRmNq8nJZPi9aPy_kIMXx49NYRHhB-57oqaGpy2UE/w:880/mb:500000/ar:1/aHR0cHM6Ly9vc2Np/bWcub3NjaGluYS5u/ZXQvb3NjbmV0L3Vw/LWQyMDhiMTE2NGQy/ZTAzMTQ5OTEzZjhk/MzEwZDhiNjk0NzEw/LnBuZw" alt="" width="880" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Monolithic Service
&lt;/h2&gt;

&lt;p&gt;The next section describes how to quickly implement a mall monolithic service based on &lt;code&gt;go-zero&lt;/code&gt;. Devs who have used &lt;code&gt;go-zero&lt;/code&gt; know that we provide an &lt;code&gt;API&lt;/code&gt; format file to describe the &lt;code&gt;Restful API&lt;/code&gt;, and then we can generate the corresponding code by &lt;code&gt;goctl&lt;/code&gt; with one command, we just need to fill in the corresponding business logic in the &lt;code&gt;logic&lt;/code&gt; files. The mall service contains several modules, and in order to make the modules independent from each other, different modules are defined by separate &lt;code&gt;API&lt;/code&gt;s, but all the &lt;code&gt;API&lt;/code&gt;s are defined for the same &lt;code&gt;service (mall-api)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;user.api&lt;/code&gt;, &lt;code&gt;order.api&lt;/code&gt;, &lt;code&gt;product.api&lt;/code&gt; and &lt;code&gt;mall.api&lt;/code&gt; in the &lt;code&gt;api&lt;/code&gt; directory, where &lt;code&gt;mall.api&lt;/code&gt; is the aggregated &lt;code&gt;api&lt;/code&gt; file. Other &lt;code&gt;api&lt;/code&gt; files are imported via &lt;code&gt;import&lt;/code&gt; directives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;api
|-- mall.api
|-- order.api
|-- product.api
|-- user.api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Mall API Definition
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;mall.api&lt;/code&gt; is defined as follows, where &lt;code&gt;syntax = "v1"&lt;/code&gt; means that this is the &lt;code&gt;v1&lt;/code&gt; syntax of &lt;code&gt;zero-api&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;syntax = "v1"

import "user.api"
import "order.api"
import "product.api"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Account module API definition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;View user details
&lt;/li&gt;
&lt;li&gt;Get all orders for a user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;user.api&lt;/code&gt; is defined 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;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;UserRequest&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;int64&lt;/span&gt; &lt;span class="s"&gt;`path:"id"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;UserReply&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;int64&lt;/span&gt;   &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;    &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
        &lt;span class="n"&gt;Balance&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"balance"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;UserOrdersRequest&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;int64&lt;/span&gt; &lt;span class="s"&gt;`path:"id"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;UserOrdersReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
        &lt;span class="n"&gt;State&lt;/span&gt;    &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="s"&gt;`json:"state"`&lt;/span&gt;
        &lt;span class="n"&gt;CreateAt&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"create_at"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;UserHandler&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;UserOrdersHandler&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserOrdersRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UserOrdersReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Order module API definition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Get order details&lt;/li&gt;
&lt;li&gt;Generate orders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;order.api&lt;/code&gt; is defined 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;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;OrderRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`path:"id"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;OrderReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt;       &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
        &lt;span class="n"&gt;State&lt;/span&gt;    &lt;span class="kt"&gt;uint32&lt;/span&gt; &lt;span class="s"&gt;`json:"state"`&lt;/span&gt;
        &lt;span class="n"&gt;CreateAt&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="s"&gt;`json:"create_at"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;OrderCreateRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ProductID&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="s"&gt;`json:"product_id"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;OrderCreateReply&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Code&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="s"&gt;`json:"code"`&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;OrderHandler&lt;/span&gt;
    &lt;span class="n"&gt;get&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;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;OrderCreateHandler&lt;/span&gt;
    &lt;span class="n"&gt;post&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;create&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderCreateRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OrderCreateReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Product module API definition
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;View product details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;product.api&lt;/code&gt; is defined 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;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"v1"&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;ProductRequest&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;int64&lt;/span&gt; &lt;span class="s"&gt;`path:"id"`&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;ProductReply&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;int64&lt;/span&gt;   &lt;span class="s"&gt;`json:"id"`&lt;/span&gt;
    &lt;span class="n"&gt;Name&lt;/span&gt;  &lt;span class="kt"&gt;string&lt;/span&gt;  &lt;span class="s"&gt;`json:"name"`&lt;/span&gt;
    &lt;span class="n"&gt;Price&lt;/span&gt; &lt;span class="kt"&gt;float64&lt;/span&gt; &lt;span class="s"&gt;`json:"price"`&lt;/span&gt;
    &lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;   &lt;span class="s"&gt;`json:"count"`&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;ProductHandler&lt;/span&gt;
    &lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;/:&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ProductReply&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Generating the monolithic service
&lt;/h3&gt;

&lt;p&gt;With the &lt;code&gt;API&lt;/code&gt; already defined, generating a service with the &lt;code&gt;API&lt;/code&gt; becomes very simple, we use &lt;code&gt;goctl&lt;/code&gt; to generate the monolithic service code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;goctl api go &lt;span class="nt"&gt;-api&lt;/span&gt; api/mall.api &lt;span class="nt"&gt;-dir&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The generated code is structured 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="o"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;api&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&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;api&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&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;api&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;etc&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yaml&lt;/span&gt;
&lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="n"&gt;internal&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;ordercreatehandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;orderhandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;producthandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;routes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;userhandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└─&lt;/span&gt; &lt;span class="n"&gt;userordershandler&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="n"&gt;logic&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├─&lt;/span&gt; &lt;span class="n"&gt;ordercreatelogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;orderlogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;productlogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;userlogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;userorderslogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="n"&gt;svc&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;servicecontext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt; &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="n"&gt;mall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's explain the generated files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;api&lt;/code&gt;: holds the &lt;code&gt;API&lt;/code&gt; description file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;etc&lt;/code&gt;: used to define the project configuration, all configuration items can be written in &lt;code&gt;mall-api.yaml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;internal/config&lt;/code&gt;: the configuration definition of the service&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;internal/handler&lt;/code&gt;: the implementation of the &lt;code&gt;handler&lt;/code&gt; corresponding to the routes defined in the &lt;code&gt;API&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;internal/logic&lt;/code&gt;: used to put the business logic corresponding to each route, the reason for the distinction between &lt;code&gt;handler&lt;/code&gt; and &lt;code&gt;logic&lt;/code&gt; is to make the business processing part as less dependent as possible, to separate &lt;code&gt;HTTP requests&lt;/code&gt; from the logic processing code, and to facilitate the subsequent splitting into &lt;code&gt;RPC service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;internal/svc&lt;/code&gt;: used to define the dependencies of the business logic processing, we can create the dependent resources in the &lt;code&gt;main&lt;/code&gt; function and pass them to &lt;code&gt;handler&lt;/code&gt; and &lt;code&gt;logic&lt;/code&gt; via &lt;code&gt;ServiceContext&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;internal/types&lt;/code&gt;: defines the &lt;code&gt;API&lt;/code&gt; request and response data structures&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mall.go&lt;/code&gt;: the file where the &lt;code&gt;main&lt;/code&gt; function is located, with the same name as the &lt;code&gt;service&lt;/code&gt; in the &lt;code&gt;API&lt;/code&gt; definition, minus the &lt;code&gt;-api&lt;/code&gt; suffix&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The generated service can be run without any modification:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;go run mall.go
Starting server at 0.0.0.0:8888...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Implementing the business logic
&lt;/h3&gt;

&lt;p&gt;Next, let's implement the business logic. The logic will be simple for demonstration purposes, not real business logic.&lt;/p&gt;

&lt;p&gt;First, let's implement the logic of getting all orders for users. Since there is no order-related information in the user module, we need to rely on the order module to query the orders of users, so we add a dependency on &lt;code&gt;OrderLogic&lt;/code&gt; in &lt;code&gt;UserOrdersLogic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserOrdersLogic&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;logx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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="n"&gt;svcCtx&lt;/span&gt;     &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceContext&lt;/span&gt;
    &lt;span class="n"&gt;orderLogic&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderLogic&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;NewUserOrdersLogic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;svcCtx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserOrdersLogic&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;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;UserOrdersLogic&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;logx&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;ctx&lt;/span&gt;&lt;span class="o"&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;svcCtx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;     &lt;span class="n"&gt;svcCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;orderLogic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NewOrderLogic&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;svcCtx&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;Implement a method in &lt;code&gt;OrderLogic&lt;/code&gt; to query all orders based on &lt;code&gt;user id&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderLogic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ordersByUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uid&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderReply&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="n"&gt;uid&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// It should actually be queried from database or cache&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;"236802838635"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;State&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="n"&gt;CreateAt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"2022-5-12 22:59:59"&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;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="s"&gt;"236802838636"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;State&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="n"&gt;CreateAt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"2022-5-10 20:59:59"&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="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;Call the &lt;code&gt;ordersByUser&lt;/code&gt; method in the &lt;code&gt;UserOrders&lt;/code&gt; method of &lt;code&gt;UserOrdersLogic&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserOrdersLogic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;UserOrders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserOrdersRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserOrdersReply&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;orders&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;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;orderLogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ordersByUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;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="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserOrdersReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Orders&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;orders&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;At this point we restart the &lt;code&gt;mall-api&lt;/code&gt; service and request all the user's orders in the browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:8888/user/123/orders
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The return result is as follows, as we expected&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;"orders"&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;"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;"236802838635"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"state"&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;"create_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-5-12 22:59:59"&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="s2"&gt;"236802838636"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"state"&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;"create_at"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2022-5-10 20:59:59"&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="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;Next we'll implement the logic for creating an order. To create an order we first need to see if the item in stock is enough, so we need to rely on the item module in the order module.&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;OrderCreateLogic&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;logx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Logger&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="n"&gt;svcCtx&lt;/span&gt;       &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceContext&lt;/span&gt;
    &lt;span class="n"&gt;productLogic&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ProductLogic&lt;/span&gt;
    &lt;span class="n"&gt;productLogic&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ProductLogic&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;NewOrderCreateLogic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;svcCtx&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;svc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ServiceContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderCreateLogic&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;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;OrderCreateLogic&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;logx&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;ctx&lt;/span&gt;&lt;span class="o"&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;svcCtx&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;       &lt;span class="n"&gt;svcCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;productLogic&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;NewProductLogic&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;svcCtx&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;The logic for creating an order is 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="k"&gt;const&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;success&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;failure&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;OrderCreateLogic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;OrderCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderCreateRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderCreateReply&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;product&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;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productLogic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;product&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;0&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;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderCreateReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;success&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OrderCreateReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;failure&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;The logic of the dependent product module is 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="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ProductLogic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductReply&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;return&lt;/span&gt; &lt;span class="n"&gt;l&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;productByID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;ProductLogic&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;productByID&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;int64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductReply&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;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;types&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ProductReply&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"apple watch 3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Price&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3333.33&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="m"&gt;99&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;The above shows that using &lt;code&gt;go-zero&lt;/code&gt; to develop a monolithic service is very simple, which helps us to develop quickly. And we also separated modules, which also provides the possibility of changing to microservices later.&lt;/p&gt;

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

&lt;p&gt;The above example shows that it is very simple to use &lt;code&gt;go-zero&lt;/code&gt; to develop monolithic services. You only need to define the &lt;code&gt;api&lt;/code&gt; file, and then the &lt;code&gt;goctl&lt;/code&gt; tool can automatically generate the project code. We only need to fill in the business logic code in the logic package. In this article we just demonstrated how to quickly develop monolithic services based on &lt;code&gt;go-zero&lt;/code&gt;, which does not involve databases. In fact, &lt;code&gt;goctl&lt;/code&gt; can also generate &lt;code&gt;CRUD&lt;/code&gt; and &lt;code&gt;cache&lt;/code&gt; code with one command.&lt;/p&gt;

&lt;p&gt;And for different business scenarios, customization can also be achieved through customizing templates. And customized templates can be shared within the team through remote &lt;code&gt;git&lt;/code&gt; repositories, which can be very efficient for team collaboration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Project address
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/zeromicro/go-zero"&gt;https://github.com/zeromicro/go-zero&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Welcome to use &lt;code&gt;go-zero&lt;/code&gt; and &lt;strong&gt;star&lt;/strong&gt; to support us! &lt;/p&gt;

</description>
      <category>go</category>
      <category>devops</category>
      <category>tutorials</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
