CRUD Micro-service with GO

aditya goel
8 min readFeb 27, 2022

In case you are landing here directly, it’s strongly suggested that you go and read through this for fundamentals.

In this blog, we shall be looking at following concepts :-

  • Demonstrating the concept of product-api micro-service.
  • Marshalling an object into JSON.
  • Explicitly writing the output to IOWriter.
  • Unmarshalling JSON into an object.
  • Demonstrating RESTful GET API with Go wrt product-api.
  • Demonstrating RESTful POST API with Go wrt product-api.
  • Demonstrating RESTful PUT API with Go wrt product-api.

Question:- Demonstrate the micro-service which shall be exposing the method to fetch products-list ?

Answer:- We want the products (i.e. list of products) to be returned through the API Call.

Step #1.) Here is how the model for products looks like. We can also specify the different names of the fields in JSON output that we might want OR we may just omit it 100% as shown below :-

Step #2.) Here is the function, which shall be returning the array of products :-

Step #3.) Here is the list of products, that we are returning. In practical world, this would come from database or some source of truth :-

Step #4.) Package “encoding/json” would allows us to marshall a struct OR Reference into JSON. Here is how the same has been done :-

Step #5.) Here is our main function, where we have defined the server and concerned handler :-

Question:- Is there a way to write output directly to IOWriter ?

Answer:- Encode() method writes JSON encoding directly to the io.Writer. It’s doing exactly the same what marshal() is doing, but instead of returning the json data to the console, it’s writing directly to the io.Writer.

Question:- Why would I just NOT use the standard marshal() ?

Answer:- It’s because of following reasons :-

  • NewEncoder() provides better performance than json.marshal(), as it doesn’t have to buffer the output into an in-memory slice of bytes.
  • This reduces allocations and the overhead of service and therefore the Encoder is marginally faster as compared to the marshal() method.
  • When a micro-service is doing multiple concurrent operations, we must think from the performance prospective. This is just a quick optimisation, and it’s just a standard programming practice.

Question:- Let’s now break the entire code using HttpVerbs for this particular Micro-Service ?

Step #1.) Let’s start with our main program. Here are set of dependencies we have mentioned into our main program :-

Step #2.) Here is how the code of our main function looks like :-

  • At line #17, we have initialised a new handler, by passing our generic logger object to it.
  • At line #23, we have created a server and the same is using multiple timeouts and custom defined address.
  • At line #31, we have started our server as part of the Go-Routine, which would start the server in an unblocking way.
  • At line #42, we are also listening to the Interrupt / Kill signals on the unbuffered blocking channel. We don’t have any other work to do in this particular main function and therefore we are happy to be blocked on this channel.

Step #3.) Here is how our handler function looks like. Note that, in above step #2, we are using the “NewProducts” method, in order to create an object of the Products handler.

Step #4.) Inside the Handler file, let’s now write this particular method “ServeHTTP()”. With this, we are checking on HTTP-VERB, if the verb being supplied is GET, then we use the function “getProducts()”, which in-fact is the part of this very same handler class. The same is defined in step #5.

Step #5.) Here is how the code of function “getProducts()” looks like.

  • Note that in below code, at line #97, we are making use of service-method “GetProducts()” from the data package. The same has been defined below in the subsequent steps.
  • Note that in below code, at line #98, We are also making use of a utility method called “ToJson()”. The same has also been defined below in the subsequent steps.

Step #6.) Here is how the code of service-method “GetProducts()” from “data” package looks like :-

  • In below code, at line #17, it indicates that this field would not be returned in this JSON.
  • At line #76, the returnType of the function “GetProducts()” is another struct: Products and we are simply returning the hard-coded list of products having 2 products in it. Simple & straightforward.
  • At line #28, note that the function “ToJson()”, we are basically making use of the NewEncoder() function and encoding the request thus received. In this case, response shall be written onto the ResponseWriter, post encoding.

Note :- At line #10 above, we have defined a Struct, which have some identifiers with it. Below defined are the meanings to the various fields and tags defined in the STRUCT :-

Step #8.) Let’s now execute the code so far and test the output :-

Step #9.) Back inside the Handler file’s ServeHTTP() method, we also check on HTTP-VERB, if the verb being supplied is POST, then we use the function “addProduct()”, which in-fact is the part of this very same handler class. The same is defined in step #10.

Step #10.) Here is how the code of function “addProduct()” looks like.

  • Note that in below code, at line #111, We are also making use of a utility method called “FromJson()”. With this method, we are reading a JSON and unmarshalling the same to an object. The same has already been defined above in step #6.
  • Note that in below code, at line #118, we are making use of service-method “AddSingleProduct()” from the data package. The same has been defined below in the subsequent steps as well.

Step #11.) Here is how the code of service-method “AddSingleProduct()” from “data” package looks like :-

  • In below code, at line #40, we are fetching the next-identifier to be used with the record (product in this case)to be added to the local data-store.
  • At line #45, we have defined a simple logic for getting the product with last identifier.
  • At line #42, we have appended (i.e. we have added new product to the data-store) to the current list of products.

Step #12.) Let’s now re-run the code and verify, whether POST is working :-

Meanwhile, let’s again fetch the products from our Micro-service. We should now have three products :-

Step #13.) Back inside the Handler file’s ServeHTTP() method, we also check on HTTP-VERB, if the verb being supplied is PUT, then we use the function “updateSingleProduct()”, which in-fact is the part of this very same handler class. The same is defined in step #14.

In below code, we are trying to extract the path-parameter from the URL, in order to know the IDENTIFIER against whom, the object is required to be updated.

Step #14.) Within the handler class, here is how the code of function “updateSingleProduct()” looks like.

  • Note that in below code, at line #77, We are also making use of a utility method called “FromJson()”. With this method, we are reading a JSON and unmarshalling the same to an object. The same has already been defined above in step #6.
  • Note that in below code, at line #84, we are making use of service-method “UpdateSingleProduct()” from the data package. The same has been defined below in the subsequent steps as well.

Step #15.) Here is how the code of service-method “UpdateSingleProduct()” from “data” package looks like :-

  • In below code, at line #67, we are fetching the product (which has to be updated) from the underlying datastore. Recall that, we are also checking whether ID of the product received through the URL is same as that of record through which we are iterating.
  • Below method “findProduct()” returns three things : product itself, index of that product and Error, if any.
  • At line #63, we are now updating the product in our datastore finally.

Step #16.) Let’s now re-run the code and verify, whether PUT is working :-

  • Note that, we basically updated the product with id value as 2.
  • We also supplied the Http-Verb as PUT using “-X” option.
  • With above operation, we had updated the Name, Description, Price and Sku.

Let’s now again get the products from the micro-service using GET verb and here are results :-

Finally, here is how our go.mod file looks like :-

That’s all in this section. If you liked reading this blog, kindly do press on clap button multiple times, to indicate your appreciation. We would see you in next series.

References :-

--

--

aditya goel

Software Engineer for Big Data distributed systems