{"id":687,"date":"2020-05-20T08:38:20","date_gmt":"2020-05-20T08:38:20","guid":{"rendered":"https:\/\/blog.samarthya.me\/wps\/?p=687"},"modified":"2020-05-20T08:39:31","modified_gmt":"2020-05-20T08:39:31","slug":"go-webservice-postget","status":"publish","type":"post","link":"https:\/\/blog.samarthya.me\/wps\/2020\/05\/20\/go-webservice-postget\/","title":{"rendered":"Go: WebService [POST][GET]"},"content":{"rendered":"\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-flow wp-block-group-is-layout-flow\">\n<h2>GOLANG<\/h2>\n<p>Go is a powerful yet simple language. The nuances of assembling a&nbsp;<strong>workspace<\/strong>, sometimes are overwhelming, yet when it comes to simplicity it is very powerful.<\/p>\n<p>In this blog, I will walk you through simple steps of writing a simple Webservice &#8216;<strong>\/users<\/strong>&#8216; which will entertain GET &amp; POST. It will respond to every other HTTP Method with a not supported error.<\/p>\n<p><img fetchpriority=\"high\" decoding=\"async\" class=\"wp-image-689 \" src=\"https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2020\/05\/GETPOST.png\" alt=\"\" width=\"302\" height=\"228\"><\/p>\n<h2>Entity: User<\/h2>\n<p>The web service will expose an object {User} or [{List of Users}]<\/p>\n<h2>Code Organization<\/h2>\n<p>Code packaging, Modules; is a tricky subject in Go. I learned from my mistakes, and even after you think you have got the hang of it, you still might get few surprises.<\/p>\n<\/div><\/div>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"761\" height=\"753\" src=\"https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2020\/05\/module2.png\" alt=\"\" class=\"wp-image-685\" srcset=\"https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2020\/05\/module2.png 761w, https:\/\/blog.samarthya.me\/wps\/wp-content\/uploads\/2020\/05\/module2-300x297.png 300w\" sizes=\"(max-width: 761px) 100vw, 761px\" \/><figcaption>Modules and Repository<\/figcaption><\/figure>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>A module is a collection of packages in go that are stored in a file tree with a&nbsp;<code>go.mod<\/code>&nbsp;file at its root.<\/p><\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Setting up the repository<\/h2>\n\n\n\n<p>Let&#8217;s create an empty directory <code>gws<\/code> in my home directory and create a directory <strong><em><code>src<\/code><\/em><\/strong> under it which should contain all the source code and sub-packages.<\/p>\n\n\n\n<p>Please note the information I am assembling is available in multitudes of blogs which leverage the official go lang documentation &amp; blogs (like&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/golang.org\/doc\/code.html#GOPATH\" target=\"_blank\">this<\/a>&nbsp;one).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Some considerations<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li>You don&#8217;t need to publish your code to a remote repository before you can build it.&nbsp;<\/li><li>A module can be defined locally without belonging to a repository.<\/li><li>An&nbsp;<dfn>import path<\/dfn>&nbsp;is a string used to import a package.<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>mkdir -p gws\/src\ncd gws\/src\ngo mod init github.com\/gws<\/code><\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>I have a habit of creating <code>src<\/code> folder, probably because of my maven days, but that is how I usually organize my code.<\/p><\/blockquote>\n\n\n\n<pre class=\"wp-block-code\"><code>> cat go.mod\n\nmodule github.com\/gws\n\ngo 1.14<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Implementation<\/h3>\n\n\n\n<p>The main package is  where the entry point for execution is defined.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">user.go<\/h4>\n\n\n\n<p>This file stores the definition of the entity that will be exposed via the rest end point<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package user\n\nimport \"encoding\/json\"\n\n\/\/User Stores the information about a user\ntype User struct {\n\tID         int    `json:\"id\"`\n\tName       string `json:\"firstName\"`\n\tMiddlename string `json:\"middleName,omitempty\"`\n\tSurname    string `json:\"lastName\"`\n\tEmail      string `json:\"userName\"`\n\tAddress    string `json:\"address\"`\n}\n\n\/\/JSONUser marshal the User to a json structure\nfunc JSONUser(user User) &#91;]byte {\n\tb, err := json.Marshal(user)\n\tif err != nil {\n\t\t\/\/ Error while unmarshaling\n\t\treturn &#91;]byte(\"\")\n\t}\n\treturn b\n}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\"><a href=\"https:\/\/golang.org\/pkg\/encoding\/json\/#pkg-overview\">encoding\/json<\/a><\/h4>\n\n\n\n<p>It exposes method <strong>Marshal<\/strong> and <strong>Unmarshal<\/strong> to do JSON translations in either direction.<\/p>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>The interface{} (empty interface) type describes an interface with zero methods. <strong>Every Go type<\/strong> implements at least zero methods and therefore satisfies the empty interface.<\/p><\/blockquote>\n\n\n\n<h4 class=\"wp-block-heading\">server.go<\/h4>\n\n\n\n<p>The server.go is created inside the <code>\/src<\/code> folder.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n    \"fmt\"\n)\n\n\/\/ main Entry point for our code.\nfunc main() {\n    fmt.Printf(\" Webservice.\\n\")\n}<\/code><\/pre>\n\n\n\n<p>The outline of the web application is <\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>One end point called&nbsp;<strong>\/api\/users&nbsp;<\/strong>which will address GET and POST request for getting &amp; adding a user respectively (defined as under)<\/li><\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">user.data.go<\/h4>\n\n\n\n<p>This is a physical grouping of all functions that will provide interface to the available users for the server.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package user\n\nimport (\n\t\"encoding\/json\"\n\t\"fmt\"\n\t\"io\/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"sort\"\n\t\"sync\"\n)\n\n\/\/ FileName filename\nconst FileName = \"users.json\"\n\n\/\/ usersMap Stores the user information in memory.\nvar usersMap = struct {\n\tsync.RWMutex\n\tu map&#91;int]User \/\/ map of users, which can be easily picked with the index\n}{u: make(map&#91;int]User)}\n\n\/\/init Initializes the usermap\nfunc init() {\n\tfmt.Println(\" loading users....\")\n\tuM, err := loadUsersMap()\n\n\tusersMap.u = uM\n\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tlog.Printf(\" Loaded %d users...\", len(usersMap.u))\n}\n\n\/\/ loadUsersMap Utility function to load the users from a file.\nfunc loadUsersMap() (map&#91;int]User, error) {\n\t\/\/ os.Stat returns the FileInfo structure describing file.\n\tif _, err := os.Stat(FileName); os.IsNotExist(err) {\n\t\treturn nil, fmt.Errorf(\"&#91;%s] does not exist\", FileName)\n\t}\n\tuserList := make(&#91;]User, 0)\n\tfile, _ := ioutil.ReadFile(FileName)\n\n\t\/\/ Unmarshal the data from the JSON file\n\terr := json.Unmarshal(&#91;]byte(file), &amp;userList)\n\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\n\tuserMap := make(map&#91;int]User)\n\n\t\/\/ for i := 0; i &lt; len(userList); i++ {\n\t\/\/ \tuserMap&#91;userList&#91;i].ID] = userList&#91;i]\n\t\/\/ }\n\n\tfor _, u := range userList {\n\t\tuserMap&#91;u.ID] = u\n\t}\n\treturn userMap, nil\n}\n\n\/\/ getUser Returns a user.\nfunc getUser(i int) *User {\n\tusersMap.RLock()\n\tdefer usersMap.RUnlock()\n\n\tfor user, ok := usersMap.u&#91;i]; ok; {\n\t\treturn &amp;user\n\t}\n\n\treturn nil\n}\n\n\/\/getUserList returns a user\nfunc getUserList() &#91;]User {\n\tusersMap.RLock()\n\tdefer usersMap.RUnlock()\n\tusers := make(&#91;]User, 0)\n\tfor _, value := range usersMap.u {\n\t\tusers = append(users, value)\n\t}\n\treturn users\n}\n\n\/\/getUserIDs Sort and return the ID's\nfunc getUserIDs() &#91;]int {\n\tusersMap.RLock()\n\tuserIds := &#91;]int{}\n\tfor key := range usersMap.u {\n\t\tuserIds = append(userIds, key)\n\t}\n\tusersMap.RUnlock()\n\tsort.Ints(userIds)\n\treturn userIds\n}\n\n\/\/getNextID returns the next available ID\nfunc getNextID() int {\n\tuserIds := getUserIDs()\n\treturn userIds&#91;len(userIds)-1] + 1\n}\n\n\/\/addOrUpdateUser handles the POST or PUT request of add or update\nfunc addOrUpdateUser(user User) (int, error) {\n\taddOrUpdateID := -1\n\tif user.ID > 0 {\n\t\toldUser := getUser(user.ID)\n\t\t\/\/ if it exists, replace it, otherwise return error\n\t\tif oldUser == nil {\n\t\t\treturn 0, fmt.Errorf(\"User-ID &#91;%d] doesn't exist\", user.ID)\n\t\t}\n\t\taddOrUpdateID = user.ID\n\t} else {\n\t\taddOrUpdateID = getNextID()\n\t\tuser.ID = addOrUpdateID\n\t}\n\n\tusersMap.Lock()\n\tusersMap.u&#91;addOrUpdateID] = user\n\tusersMap.Unlock()\n\treturn addOrUpdateID, nil\n}<\/code><\/pre>\n\n\n\n<p>I am not using any database, so will be using in memory object to store few users that will respond appropriately to the HTTP methods when invoked.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ usersMap Stores the user information in memory.\nvar usersMap = struct {\n\tsync.RWMutex\n\tu map&#91;int]User \/\/ map of users, which can be easily picked with the index\n}{u: make(map&#91;int]User)}<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">user.service.go<\/h4>\n\n\n\n<p>It uses the&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/golang.org\/pkg\/net\/http\/\" target=\"_blank\">&#8220;net\/http&#8221;<\/a>&nbsp;package which provides the client and the server configurations.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package user\n\nimport (\n\t\"encoding\/json\"\n\t\"fmt\"\n\t\"io\/ioutil\"\n\t\"log\"\n\t\"net\/http\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nconst userPath string = \"users\"\n\n\/\/ SetupService Service end point\nfunc SetupService(basePath string) {\n\t\/\/ The HandlerFunc type is an adapter to allow the use of ordinary functions as HTTP handlers.\n\tusersHandler := http.HandlerFunc(HandleUsers)\n\tuserHandler := http.HandlerFunc(HandleUser)\n\thttp.Handle(fmt.Sprintf(\"%s\/%s\", basePath, userPath), usersHandler)\n\thttp.Handle(fmt.Sprintf(\"%s\/%s\/\", basePath, userPath), userHandler)\n}\n\n\/\/ HandleUsers Will expose this API to handle user commands\nfunc HandleUsers(w http.ResponseWriter, r *http.Request) {\n\t\/\/ Handlers can handle request with multiple request methods.\n\t\/\/ Every request has a method a simple string\n\tswitch r.Method {\n\tcase http.MethodGet:\n\t\tlog.Println(\" GET: called\")\n\n\t\t\/\/ Get the list of users.\n\t\tusers := getUserList()\n\n\t\t\/\/Marshal the userlist\n\t\tb, err := json.Marshal(users)\n\t\tif err != nil {\n\t\t\t\/\/ Error while unmarshaling\n\t\t\tw.WriteHeader(http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusOK)\n\t\tw.Header().Add(\"Content-Type\", \"application\/json\")\n\t\tw.Write(b)\n\n\tcase http.MethodPost:\n\t\tlog.Println(\" POST: called\")\n\t\tvar newUser User\n\t\te, er := ioutil.ReadAll(r.Body)\n\t\tif er != nil {\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\n\t\ter = json.Unmarshal(e, &amp;newUser)\n\t\tif er != nil {\n\t\t\t\/\/ Error unmarsheling the data\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t}\n\n\t\tfmt.Printf(\" User : %s\", newUser.Email)\n\n\t\t_, err := addOrUpdateUser(newUser)\n\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\tw.WriteHeader(http.StatusCreated)\n\t\tw.Header().Add(\"Content-Type\", \"application\/json\")\n\t\tw.Write(JSONUser(newUser))\n\n\tcase http.MethodOptions:\n\t\treturn\n\n\tdefault:\n\t\tlog.Printf(\" Method: %s\\n\", r.Method)\n\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t\tw.Header().Add(\"Content-Type\", \"application\/json\")\n\t\tw.Write(&#91;]byte(\"{msg: method not supported}\"))\n\t}\n\n}\n\n\/\/ HandleUser For a single user request\nfunc HandleUser(w http.ResponseWriter, r *http.Request) {\n\t\/\/ URL specifies either the URI being requested (for server\n\t\/\/ requests) or the URL to access (for client requests).\n\turlPathSegments := strings.Split(r.URL.Path, fmt.Sprintf(\"%s\/\", userPath))\n\n\tif len(urlPathSegments&#91;1:]) > 1 {\n\t\tw.WriteHeader(http.StatusBadRequest)\n\t\treturn\n\t}\n\n\t\/\/Convert the last element of the slice (should be an int)\n\tuserID, err := strconv.Atoi(urlPathSegments&#91;len(urlPathSegments)-1])\n\tif err != nil {\n\t\tlog.Print(err)\n\t\tw.WriteHeader(http.StatusNotFound)\n\t\treturn\n\t}\n\n\t\/\/userID will be used in the switch below based on the HTTP method\n\tswitch r.Method {\n\tcase http.MethodGet:\n\t\tuser := getUser(userID)\n\t\tif user == nil {\n\t\t\tw.WriteHeader(http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\t\tj, err := json.Marshal(user)\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\t_, err = w.Write(j)\n\t\tif err != nil {\n\t\t\tlog.Fatal(err)\n\t\t}\n\n\tcase http.MethodPut:\n\t\tvar user User\n\t\terr := json.NewDecoder(r.Body).Decode(&amp;user)\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t\tif user.ID != userID {\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\tw.Write(&#91;]byte(\"{ msg: id supplied in request and in body mismatch}\"))\n\t\t\treturn\n\t\t}\n\t\t_, err = addOrUpdateUser(user)\n\t\tif err != nil {\n\t\t\tlog.Print(err)\n\t\t\tw.WriteHeader(http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\tcase http.MethodDelete:\n\t\t\/\/deleteUser(userID)\n\n\tcase http.MethodOptions:\n\t\treturn\n\tdefault:\n\t\tw.WriteHeader(http.StatusMethodNotAllowed)\n\t}\n}\n<\/code><\/pre>\n\n\n\n<p>Time to modify the <code>server.go<\/code> to use the <code>\/users<\/code> service.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"net\/http\"\n\n\tu \"github.com\/gws\/user\"\n)\n\n\/\/ PathAPI API path to be used as base\nconst PathAPI string = \"\/api\"\n\n\/\/ main Entry point for our code.\nfunc main() {\n\tfmt.Printf(\" Webservice.\\n\")\n\t\/\/hell.SetupService(PathAPI)\n\tu.SetupService(PathAPI)\n\tlog.Fatal(http.ListenAndServe(\":8090\", nil))\n}\n<\/code><\/pre>\n\n\n\n<h3 class=\"wp-block-heading\">Points to remember<\/h3>\n\n\n\n<ul class=\"wp-block-list\"><li>Import the package&nbsp;<strong>user<\/strong>&nbsp;defined<\/li><\/ul>\n\n\n\n<pre class=\"wp-block-code\"><code>import ( \n    u \"github.com\/gws\/user\"\n)<\/code><\/pre>\n\n\n\n<ul class=\"wp-block-list\"><li><strong>u.SetupService<\/strong>&nbsp;: It allows adding a base path for the endpoint exposed. In our example we are using &#8216;\/api\/users&#8217;<\/li><li>http.ListenAndServer : It starts an HTTP server with a given address and handler. In our case the handler are setup in the&nbsp;<strong>SetupService<\/strong>&nbsp;method of package.<\/li><\/ul>\n\n\n\n<p>All the code is available in my&nbsp;<a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/samarthya\/gws\" target=\"_blank\">gitrepo<\/a>.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">References<\/h2>\n\n\n\n<ul class=\"wp-block-list\"><li><a href=\"https:\/\/golang.org\/cmd\/go\/#hdr-Preliminary_module_support\">https:\/\/golang.org\/cmd\/go\/#hdr-Preliminary_module_support<\/a><\/li><li>https:\/\/golang.org\/pkg\/sync\/<\/li><li>https:\/\/golang.org\/pkg\/sync\/#RWMutex<\/li><li>For more links visit <a href=\"https:\/\/blog.samarthya.me\/wps\/2020\/05\/19\/go-helpful-links\/\" target=\"_blank\" rel=\"noreferrer noopener\">here<\/a><\/li><\/ul>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>GOLANG Go is a powerful yet simple language. The nuances of assembling a&nbsp;workspace, sometimes are overwhelming, yet when it comes to simplicity it is very powerful. In this blog, I will walk you through simple steps of writing a simple Webservice &#8216;\/users&#8216; which will entertain GET &amp; POST. It will respond to every other HTTP [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":689,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"image","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[34],"tags":[75,23,74,73],"class_list":["post-687","post","type-post","status-publish","format-image","has-post-thumbnail","hentry","category-technical","tag-get","tag-golang","tag-post","tag-webservice","post_format-post-format-image"],"_links":{"self":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/687","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/comments?post=687"}],"version-history":[{"count":0,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/posts\/687\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media\/689"}],"wp:attachment":[{"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/media?parent=687"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/categories?post=687"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.samarthya.me\/wps\/wp-json\/wp\/v2\/tags?post=687"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}