{"id":97350,"date":"2023-08-04T12:27:42","date_gmt":"2023-08-04T12:27:42","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=97350"},"modified":"2023-10-09T13:29:30","modified_gmt":"2023-10-09T13:29:30","slug":"building-rest-apis-in-go-with-mux-and-gorm","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/development\/other-development\/building-rest-apis-in-go-with-mux-and-gorm\/","title":{"rendered":"Building REST APIs in Go with Mux and GORM"},"content":{"rendered":"<p>In modern software development, Application Programming Interfaces (APIs) are essential for building scalable and flexible systems. APIs enable applications to communicate and exchange data, amongst other actions.<\/p>\n<p>Representational State Transfer (REST) is an API specification for building simple, scalable, client-server APIs based on HTTP, stateless, cacheable, and layered.<\/p>\n<p>RESTful APIs provide a medium for interaction between software components, easing the building process of distributed applications. However, building RESTful APIs can be daunting, especially for beginners; that\u2019s where the Gorilla Mux package comes in handy.<\/p>\n<p>The Gorilla Mux package is a powerful HTTP router and dispatcher that simplifies building RESTful APIs. Gorilla Mux allows you to define routes for different HTTP methods (<code>GET<\/code>, <code>POST<\/code>, <code>PUT<\/code>, <code>DELETE<\/code>, etc.) and handle requests and responses in a structured manner. The Gorilla Mux package is easy to use, and the package supports a range of middleware that you can use for logging and authentication operations, among others.<\/p>\n<h2><a id=\"post-97350-_76ysrrknnmw6\"><\/a>Getting Started Building Applications in Go<\/h2>\n<p>Getting started with building REST APIs with Go is quite easy. First, you must install the latest Go version on your system. The installation process is straightforward. Simply visit the Go downloads webpage to install the Go binary distribution for your computer\u2019s operating system.<\/p>\n<p>Run this command on your terminal to verify that you\u2019ve successfully installed Go.<\/p>\n<pre class=\"lang:tsql theme:ssms2012-simple-talk\">go version<\/pre>\n<p>Once you have installed Go, the next step is creating a new directory and initializing the directory as a Go project.<\/p>\n<p>Run these commands on your terminal to create and initialize a new Go project on your computer.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">mkdir HumanAPI &amp;&amp; cd HumanAPI\r\ngo mod init HumanAPI<\/pre>\n<p>The <code>go mod<\/code> command initializes a new Go project in the specified working directory. The command also creates a go.mod file in the directory for managing your project\u2019s dependencies.<\/p>\n<p>Finally, you\u2019ll need some form of persistence for your database. In this tutorial, you\u2019ll learn how to use GORM and a SQL database for persistence for your API. GORM supports a variety of SQL databases, including MSSQL, MySQL, and PostgreSQL. Install your preferred database management system, and you\u2019re good to go.<a id=\"post-97350-_toxqnn1w2lnq\"><\/a><\/p>\n<h2>Building APIs with Gorilla Mux<\/h2>\n<p>The <a href=\"https:\/\/github.com\/gorilla\/mux\/blob\/main\/README.md\">Gorilla Mux<\/a> package is a third-party package, and you\u2019ll need to install the package as one of your project\u2019s dependencies to get started.<\/p>\n<p>Run this command in the terminal of your project\u2019s working directory to install the Gorilla Mux package.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">go get github.com\/gorilla\/mux<\/pre>\n<p>Here\u2019s how to import the Gorilla Mux package into your Go files.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">import \"github.com\/gorilla\/mux\"<\/pre>\n<p>You\u2019ll need to create a new router instance to work with handler functions with the Gorilla Mux package. You can use the <code>NewRouter<\/code> function to create a new router instance.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">router := mux.NewRouter()<\/pre>\n<p>After creating a router instance, you can use the <code>HandleFunc<\/code> function to map handler functions to routes and specify the HTTP method for the routes.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func main() {\r\n\trouter := mux.NewRouter()\r\n \trouter.HandleFunc(\"\/humans\/{id}\",   \r\n                    getHuman).Methods(\"GET\")\r\n\trouter.HandleFunc(\"\/humans\", createHuman).Methods(\"POST\")\r\n\trouter.HandleFunc(\"\/humans\/{id}\", \r\n                    updateHuman).Methods(\"PUT\")\r\n\trouter.HandleFunc(\"\/humans\/{id}\", \r\n                    deleteHuman).Methods(\"DELETE\")\r\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\r\n}<\/pre>\n<p>The <strong>main<\/strong> function above creates a new router instance and mounts routes to <code>GET<\/code>, <code>POST<\/code>, <code>PUT<\/code>, and <code>DELETE<\/code> requests before starting a server on port <code>:8080<\/code> with the <code>ListenAndServe<\/code> function of the <code>http<\/code> package.<\/p>\n<h2><a id=\"post-97350-_yz9iilb4rvdg\"><\/a>Setting Persistence Up GORM for the API<\/h2>\n<p>Most of the time, you\u2019ll need persistence when building APIs for data storage and retrieval.<a href=\"https:\/\/www.red-gate.com\/simple-talk\/development\/other-development\/how-to-use-any-sql-database-in-go-with-gorm\/\"> GORM<\/a> is the most popular ORM in the Go ecosystem, and the package is useful for working with many databases.<\/p>\n<p>Run this command to install the GORM package and the SQLite database driver for the package.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">go get gorm.io\/gorm\r\ngo get gorm.io\/driver\/sqlite \/\/SQLite<\/pre>\n<p>You can learn more about GORM from this article if you\u2019re unfamiliar with the package. The article covers the most popular operations with the package while considering other databases.<\/p>\n<p>Here\u2019s the list of imports you\u2019ll need to set up the API, including Gorilla Mux, GORM, and Go built-in packages.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">import(\r\n   \"encoding\/json\"\r\n   \"fmt\"\r\n   \"log\"\r\n   \"net\/http\"\r\n   \"github.com\/gorilla\/mux\"\r\n   \"gorm.io\/driver\/sqlite\"\r\n   \"gorm.io\/gorm\"\r\n)<\/pre>\n<p>You\u2019ll need a struct model that defines the database schema for queries and data migration. Here\u2019s an example struct for the database schema.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">type Human struct {\r\n\tID   uint   `gorm:\"primaryKey\"`\r\n\tAge  int    `json:\"age\"`\r\n\tName string `json:\"name\"`\r\n}<\/pre>\n<p>The <code>ID<\/code> field is the primary key, and the <code>Age<\/code> and <code>Name<\/code> fields are regular fields.<\/p>\n<p>You\u2019ll need to access your database instance from multiple handler functions, so you can resort to making it a global variable for accessibility. The <code>DB<\/code> struct defines a GORM database instance.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">var (\r\n\tdb  *gorm.DB\r\n\terr error\r\n)<\/pre>\n<p>You can use a function to manage database auto migrations. You\u2019ll use the <code>Open<\/code> function of the <code>gorm<\/code> package to open a database connection from the driver. The <code>sqlite<\/code> package\u2019s <code>Open<\/code> function returns a connection instance that GORM can access and return a database instance.<\/p>\n<p>After creating a database instance, you can use the <code>AutoMigrate<\/code> function of the database instance that takes in the struct model and auto-migrates struct instances.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func DBConnection() error {\r\n\tdb, err = gorm.Open(sqlite.Open(\"test.db\"), &amp;gorm.Config{})\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\terr = db.AutoMigrate(&amp;Human{})\r\n\tif err != nil {\r\n\t\treturn err\r\n\t}\r\n\treturn nil\r\n}<\/pre>\n<p>The <code>DBConnection<\/code> function is the auto migration function. The function returns an error if there\u2019s any during the migration process.<\/p>\n<p>You can proceed to call the <code>DBConnection<\/code> function in the <code>main<\/code> function.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func main() {\r\n\terr := DBConnection()\r\n\tif err != nil {\r\n\t\tlog.Fatal(\"Database connection error\", err)\r\n\t}\r\n\trouter := mux.NewRouter()\r\n\trouter.HandleFunc(\"\/humans\/{id}\", \r\n                 getHuman).Methods(\"GET\")\r\n\trouter.HandleFunc(\"\/humans\", createHuman).Methods(\"POST\")\r\n\trouter.HandleFunc(\"\/humans\/{id}\", \r\n                 updateHuman).Methods(\"PUT\")\r\n\trouter.HandleFunc(\"\/humans\/{id}\", \r\n                 deleteHuman).Methods(\"DELETE\")\r\n\tlog.Fatal(http.ListenAndServe(\":8080\", router))\r\n}<\/pre>\n<p>The next step is setting up the handler functions for successful operations.<\/p>\n<h2><a id=\"post-97350-_5aqptd4soyy1\"><\/a>The POST Request Handler Function<\/h2>\n<p>Your POST request handler function would receive a JSON request body from the client, decode the JSON into the <code>Human<\/code> struct instance and migrate the struct to the database using the <code>Create<\/code> function of the database instance.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func createHuman(writer http.ResponseWriter, \r\n             request *http.Request) {\r\n\tvar human Human\r\n\terr = json.NewDecoder(request.Body).Decode(&amp;human)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n\tdb.Create(&amp;human)\r\n\terr := json.NewEncoder(writer).Encode(human)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n}<\/pre>\n<p>The <code>createHuman<\/code> handler function creates a handler function instance with HTTP response writer and requests instances as arguments, decodes the JSON to struct with the <code>Decode<\/code> function of the <code>NewDecoder<\/code> function, migrates the data to the database, and returns an encoded JSON struct to the client.<\/p>\n<p>Here\u2019s a CURL request that makes a POST request to the server for the <code>\/humans<\/code> route.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">curl -X POST -H \"Content-Type: application\/json\" \r\n   -d '{\"name\":\"John Doe\",\"age\":30}' &lt;http:\/\/localhost:8080\/humans&gt; <\/pre>\n<h2><a id=\"post-97350-_7urwme3o7qnw\"><\/a>The GET Request Handler Function<\/h2>\n<p>Your <code>GET<\/code> request handler function will receive an <code>ID<\/code> from the client\u2019s request, search through the database for a row with the <code>ID<\/code> and return the row&#8217;s data from the database as JSON.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func getHuman(writer http.ResponseWriter, request *http.Request) {\r\n\tvars := mux.Vars(request)\r\n\tid := vars[\"id\"]\r\n\tvar human Human\r\n\tdb.First(&amp;human, id)\r\n\terr := json.NewEncoder(writer).Encode(human)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n}<\/pre>\n<p>The <code>getHuman<\/code> handler function accesses the data from the request using the <code>Vars<\/code> function of the <code>mux<\/code> package and retrieves the ID.<\/p>\n<p>The <code>human<\/code> variable is an instance of the <code>Human<\/code> struct created to hold the row&#8217;s data with the ID, and the <code>Encode<\/code> function of the <code>NewEncoder<\/code> function of the JSON package encodes the <code>human<\/code> struct instance to the client as a response.<\/p>\n<p>Here\u2019s the CURL request that makes a <code>GET<\/code> to the server requesting data 1 as the ID.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">curl &lt;http:\/\/localhost:8080\/humans\/1&gt; <\/pre>\n<p>Here\u2019s the result of the request. The request returns the data inserted into the database with the <code>POST<\/code> request.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"1934\" height=\"922\" class=\"wp-image-97357\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97350-1-2.png\" \/><\/p>\n<h2><a id=\"post-97350-_qhzao2uwkugz\"><\/a>The PUT Request Handler Function<\/h2>\n<p>The <code>PUT<\/code> request handler function would retrieve an ID from the request <code>URL<\/code> and a JSON payload from the request body and update the <code>ID<\/code> row with the JSON from the request body.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func updateHuman(writer http.ResponseWriter, \r\n                      request *http.Request) {\r\n\tvars := mux.Vars(request)\r\n\tid := vars[\"id\"]\r\n\tvar human Human\r\n\tdb.First(&amp;human, id)\r\n\terr := json.NewDecoder(request.Body).Decode(&amp;human)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n\tdb.Save(&amp;human)\r\n\terr = json.NewEncoder(writer).Encode(human)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n}<\/pre>\n<p>The <strong>updateHuman<\/strong> handler function extracts the ID from the request just like the GET request and retrieves the data with the ID from the database. If the retrieval is successful, the data exists. The <strong>Save<\/strong> function of the database instance updates the database with the JSON from the body of the request and returns the JSON to the client after successfully updating the database.<\/p>\n<p>The CURL request for the PUT request holds the payload with different <strong>name<\/strong> and <strong>age<\/strong> fields from the current data in the database with the ID of 1.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">curl -X PUT -H \"Content-Type: application\/json\" \r\n   -d '{\"name\":\"Jane Doe\",\"age\":35}' &lt;http:\/\/localhost:8080\/humans\/1&gt;<\/pre>\n<p>On sending the CURL request, here\u2019s the result of the update operation.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"734\" class=\"wp-image-97358\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97350-2-2.png\" \/><\/p>\n<h2><a id=\"post-97350-_akzl3nnwzxex\"><\/a>The DELETE Request Handler Function<\/h2>\n<p>Your <code>DELETE<\/code> request handler function would retrieve an <code>ID<\/code> from the request and delete the row with the <code>ID<\/code> from the database before responding to the client to signal a successful delete operation.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">func deleteHuman(writer http.ResponseWriter, \r\n                      request *http.Request) {\r\n\tvars := mux.Vars(request)\r\n\tid := vars[\"id\"]\r\n\tdb.Delete(&amp;Human{}, id)\r\n\t_, err := fmt.Fprintf(writer, \r\n                 \"Human with ID = %s has been deleted\", id)\r\n\tif err != nil {\r\n\t\tlog.Println(err)\r\n\t}\r\n} <\/pre>\n<p>The <code>deleteHuman<\/code> function retrieves the ID from the client\u2019s request URL and deletes the row using the <code>Delete<\/code> function of the database instance.<\/p>\n<p>After a successful deletion operation, the function writes a string with the <code>ID<\/code> to the client.<\/p>\n<p>Here\u2019s the <code>CURL<\/code> request for the <code>DELETE<\/code> request. The client requests to delete the row with ID 1.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">curl -X DELETE &lt;http:\/\/localhost:8080\/humans\/1&gt;<\/pre>\n<p>On sending the CURL request, here\u2019s the result of the update operation.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"2048\" height=\"838\" class=\"wp-image-97359\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2023\/07\/word-image-97350-3-2.png\" \/><\/p>\n<h2><a id=\"post-97350-_gsfqcorptwcx\"><\/a>Conclusion<\/h2>\n<p>You\u2019ve learned about RESTful APIs, the Gorilla Mux package, how to use GORM for persistence when building APIs, how to create router instances, mount routes to handler functions, and how to use the Gorilla Mux package to interact with requests.<\/p>\n<p>Using GORM and Gorilla Mux can help you build scalable, maintainable APIs that handle many HTTP requests efficiently.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In modern software development, Application Programming Interfaces (APIs) are essential for building scalable and flexible systems. APIs enable applications to communicate and exchange data, amongst other actions. Representational State Transfer (REST) is an API specification for building simple, scalable, client-server APIs based on HTTP, stateless, cacheable, and layered. RESTful APIs provide a medium for interaction&#8230;&hellip;<\/p>\n","protected":false},"author":340771,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,147591],"tags":[],"coauthors":[147592],"class_list":["post-97350","post","type-post","status-publish","format-standard","hentry","category-featured","category-other-development"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97350","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/340771"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=97350"}],"version-history":[{"count":3,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97350\/revisions"}],"predecessor-version":[{"id":97362,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/97350\/revisions\/97362"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=97350"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=97350"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=97350"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=97350"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}