{"id":12572,"date":"2025-01-13T07:29:47","date_gmt":"2025-01-13T07:29:47","guid":{"rendered":"https:\/\/myprojects.advchaweb.com\/?p=12572"},"modified":"2025-01-13T10:37:20","modified_gmt":"2025-01-13T10:37:20","slug":"golang-and-gin-restful-api","status":"publish","type":"post","link":"https:\/\/myprojects.advchaweb.com\/index.php\/2025\/01\/13\/golang-and-gin-restful-api\/","title":{"rendered":"Golang and Gin Restful API"},"content":{"rendered":"<p>Ref: https:\/\/santrikoding.com\/tutorial-restful-api-golang-1-membuat-project-golang<\/p>\n<p>Note: Make sure golang is already installed by checking with &#8216;go version&#8217; on your linux terminal<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~$ go version\r\ngo version go1.18.3 linux\/amd64<\/pre>\n<p>[\/codesyntax]<br \/>\nNote: it&#8217;ll be better to use the newest go version. I already installed go version 1.23.4<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Downloads$ go version\r\ngo version go1.23.4 linux\/amd64<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>Note: don&#8217;t forget to run &#8216;go mod tidy&#8217; on your go project<\/p>\n<p>1. Create a new directory for this project named &#8216;go-restful-api&#8217; then go into the directory<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects$ mkdir go-restful-api\r\nsatria@teddy:~\/Documents\/projects$ cd go-restful-api\/<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>then type this to create a new module &#8216;advcha\/backend-api&#8217;<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects\/go-restful-api$ go mod init advcha\/backend-api\r\ngo: creating new go.mod: module advcha\/backend-api<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>2. Install &#8216;Gin&#8217; and the libraries. Gin is a go-based web framework<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects\/go-restful-api$ go get -u github.com\/gin-gonic\/gin\r\ngo: downloading github.com\/gin-gonic\/gin v1.10.0\r\n...\r\ngithub.com\/gin-gonic\/gin imports\r\n\tgithub.com\/gin-gonic\/gin\/binding imports\r\n\tgithub.com\/pelletier\/go-toml\/v2 imports\r\n\tslices: package slices is not in GOROOT (\/usr\/local\/go\/src\/slices)<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>3. Create a &#8216;Hello World&#8217; with Gin<br \/>\ncreate a new file &#8216;main.go&#8217; then here is the content<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>package main\r\n\r\nimport (\r\n\t\"github.com\/gin-gonic\/gin\"\r\n)\r\n\r\nfunc main() {\r\n\t\/\/ initialize Gin\r\n\trouter := gin.Default()\r\n\r\n\t\/\/ create a GET route with an endpoint \"\/\"\r\n\trouter.GET(\"\/\", func(c *gin.Context) {\r\n\t\t\/\/ return JSON response\r\n\t\tc.JSON(200, gin.H{\r\n\t\t\t\"message\": \"Hello World!\",\r\n\t\t})\r\n\t})\r\n\r\n\t\/\/ start the server with port 3000\r\n\trouter.Run(\":3000\") \/\/ listen and serve on\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>4. Run it with &#8216;go run main.go&#8217;<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects\/go-restful-api$ go run main.go\r\n[GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.\r\n\r\n[GIN-debug] [WARNING] Running in \"debug\" mode. Switch to \"release\" mode in production.\r\n - using env:\texport GIN_MODE=release\r\n - using code:\tgin.SetMode(gin.ReleaseMode)\r\n\r\n[GIN-debug] GET    \/                         --&gt; main.main.func1 (3 handlers)\r\n[GIN-debug] [WARNING] You trusted all proxies, this is NOT safe. We recommend you to set a value.\r\nPlease check https:\/\/pkg.go.dev\/github.com\/gin-gonic\/gin#readme-don-t-trust-all-proxies for details.\r\n[GIN-debug] Listening and serving HTTP on :3000<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>5. open it on your browser with http:\/\/localhost:3000\/<br \/>\nit should print<\/p>\n<pre>{\"message\":\"Hello World!\"}<\/pre>\n<p>Install GORM (Go ORM). it&#8217;s a Object Relational Mapping (ORM) for Golang<br \/>\n1. Install GORM with MySQL driver<br \/>\n[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects\/go-restful-api$ go get -u gorm.io\/gorm gorm.io\/driver\/mysql\r\ngo: downloading gorm.io\/gorm v1.25.12\r\ngo: downloading gorm.io\/driver\/mysql v1.5.7\r\ngo: downloading github.com\/go-sql-driver\/mysql v1.7.0\r\ngo: downloading github.com\/jinzhu\/now v1.1.5\r\ngo: downloading github.com\/jinzhu\/inflection v1.0.0\r\ngo: downloading github.com\/go-sql-driver\/mysql v1.8.1\r\ngo: downloading filippo.io\/edwards25519 v1.1.0\r\ngo: added filippo.io\/edwards25519 v1.1.0\r\ngo: added github.com\/go-sql-driver\/mysql v1.8.1\r\ngo: added github.com\/jinzhu\/inflection v1.0.0\r\ngo: added github.com\/jinzhu\/now v1.1.5\r\ngo: upgraded golang.org\/x\/text v0.15.0 =&gt; v0.21.0\r\ngo: added gorm.io\/driver\/mysql v1.5.7\r\ngo: added gorm.io\/gorm v1.25.12<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>2. Create a new .env file to store the variables like the database name, password, etc.<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>export DB_USERNAME=your_mysql_username\r\nexport DB_PASSWORD=your_mysql_password\r\nexport DB_HOST=127.0.0.1\r\nexport DB_PORT=3306\r\nexport DB_NAME=db_go_restful_api<\/pre>\n<p>[\/codesyntax]<br \/>\nNote: rename &#8216;your_mysql_username&#8217; and &#8216;your_mysql_password&#8217; for your mysql account<br \/>\n&#8216;db_go_restful_api&#8217; is the database name we will create later<\/p>\n<p>We need to install a package &#8216;github.com\/joho\/godotenv&#8217; on the terminal &#8216;go get github.com\/joho\/godotenv&#8217; to read the .env file<br \/>\nNote: run &#8216;go mod tidy&#8217; to install any missing packages if exist<\/p>\n<p>2. Create a Post model<br \/>\ncreate a new directory &#8216;models&#8217; then create a new file &#8216;post.go&#8217; in it. here is the file content<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<p>&nbsp;<\/p>\n<pre>package models\r\n\r\ntype Post struct {\r\n\t\/\/ ID is the unique identifier of the post\r\n\tID \tint \t`json:\"id\" gorm:\"primary_key\"`\r\n\t\/\/ Title is the title of the post\r\n\tTitle \tstring \t`json:\"title\"`\r\n\t\/\/ Content is the content of the post\r\n\tContent string \t`json:\"content\"`\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>3. create a database connection<br \/>\ncreate a new file &#8216;setup.go&#8217; in the &#8216;models&#8217; directory. here is the file content<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>package models\r\n\r\nimport (\r\n\t\"fmt\"\r\n\t\"os\"\r\n\t\"gorm.io\/driver\/mysql\"\r\n\t\"gorm.io\/gorm\"\r\n)\r\n\r\nvar DB *gorm.DB\r\n\r\nfunc ConnectDatabase() {\r\n\t\/\/ create a database connection. The connection string is in the format:\r\n\tusername := os.Getenv(\"DB_USERNAME\")\r\n\tpassword := os.Getenv(\"DB_PASSWORD\")\r\n\thost := os.Getenv(\"DB_HOST\")\r\n\tport := os.Getenv(\"DB_PORT\")\r\n\tdbname := os.Getenv(\"DB_NAME\")\r\n\r\n\tdsn := fmt.Sprintf(\"%s:%s@tcp(%s:%s)\/%s?charset=utf8mb4&amp;parseTime=True&amp;loc=Local\",\r\n\t\tusername, password, host, port, dbname)\r\n\t\r\n\tdatabase, err := gorm.Open(mysql.Open(dsn), &amp;gorm.Config{})\r\n\r\n\t\/\/ check if there is an error when connecting to the database\r\n\tif err != nil {\r\n\t\tpanic(\"Failed to connect to database!\")\r\n\t}\r\n\r\n\t\/\/ if there is no error, then create a table for the 'Post' model\r\n\tdatabase.AutoMigrate(&amp;Post{})\r\n\r\n\t\/\/ assign the database connection to the global variable 'DB'\r\n\tDB = database\r\n}\r\n\r\nfunc GetDB() *gorm.DB {\r\n\treturn DB\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>4. create a new mysql database &#8216;db_go_restful_api&#8217;<\/p>\n<p>5. Create a new Post controller &#8216;postController.go&#8217; in &#8216;controllers&#8217; directory<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>package controllers\r\n\r\nimport (\r\n\t\"advcha\/backend-api\/models\"\r\n\t\"github.com\/gin-gonic\/gin\"\r\n)\r\n\r\n\/\/ get all posts\r\nfunc FindPosts(c *gin.Context) {\r\n\t\/\/ get all posts from the database\r\n\tvar posts []models.Post\r\n\tmodels.DB.Find(&amp;posts)\r\n\r\n\t\/\/ return JSON response\r\n\tc.JSON(200, gin.H{\r\n\t\t\"status\": \"success\",\r\n\t\t\"message\": \"All posts retrieved successfully\",\r\n\t\t\"data\": posts\r\n\t})\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>6. Create a route API Post<br \/>\nedit main.go to import the models and controllers. Also put the route in it. so it&#8217;ll be like this<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>package main\r\n\r\nimport (\r\n\t\"advcha\/backend-api\/controllers\"\r\n\t\"advcha\/backend-api\/models\"\r\n\t\"github.com\/joho\/godotenv\"\r\n\t\"github.com\/gin-gonic\/gin\"\r\n\t\"log\"\r\n)\r\n\r\nfunc main() {\r\n\t\/\/ load the .env file\r\n\terr := godotenv.Load()\r\n\tif err != nil {\r\n\t\tlog.Fatal(\"Error loading .env file\")\r\n\t}\r\n\r\n\t\/\/ initialize Gin\r\n\trouter := gin.Default()\r\n\r\n\t\/\/ connect to the database\r\n\tmodels.ConnectDatabase()\r\n\r\n\t\/\/ create a GET route with an endpoint \"\/\"\r\n\trouter.GET(\"\/\", func(c *gin.Context) {\r\n\t\t\/\/ return JSON response\r\n\t\tc.JSON(200, gin.H{\r\n\t\t\t\"message\": \"Hello World!\",\r\n\t\t})\r\n\t})\r\n\r\n\t\/\/ create a GET route with an endpoint \"\/posts\"\r\n\trouter.GET(\"\/api\/posts\", controllers.FindPosts)\r\n\r\n\t\/\/ start the server with port 3000\r\n\trouter.Run(\":3000\") \/\/ listen and serve on\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>&nbsp;<\/p>\n<p>7. Run it and open it on your browser<br \/>\nIf everything okay, the url http:\/\/localhost:3000\/api\/posts will show<\/p>\n<pre>{\"data\":[],\"message\":\"All posts retrieved successfully\",\"status\":\"success\"}<\/pre>\n<p>Note: Also we can check it via Postman<br \/>\ncreate a new collection &#8216;Go Gin Restful API&#8217; then create a new GET request &#8216;api_posts&#8217; with url http:\/\/localhost:3000\/api\/posts<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-12588\" src=\"http:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api.png\" alt=\"\" width=\"811\" height=\"392\" srcset=\"https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api.png 1608w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api-300x145.png 300w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api-1024x495.png 1024w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api-768x371.png 768w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api-1536x742.png 1536w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-api-1200x580.png 1200w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 984px) 61vw, (max-width: 1362px) 45vw, 600px\" \/><\/p>\n<p>Insert data into the database<br \/>\n1. Create a new function &#8216;InsertPost&#8217; in postController.go<br \/>\nnote: first, we need to install a package &#8216;github.com\/go-playground\/validator\/v10&#8242;[codesyntax lang=&#8221;bash&#8221;]<\/p>\n<pre>satria@teddy:~\/Documents\/projects\/go-restful-api$ go get github.com\/go-playground\/validator\/v10\r\ngo: upgraded github.com\/gabriel-vasile\/mimetype v1.4.3 =&gt; v1.4.8\r\ngo: upgraded github.com\/go-playground\/validator\/v10 v10.20.0 =&gt; v10.24.0\r\ngo: upgraded golang.org\/x\/crypto v0.23.0 =&gt; v0.32.0\r\ngo: upgraded golang.org\/x\/net v0.25.0 =&gt; v0.34.0\r\ngo: upgraded golang.org\/x\/sys v0.20.0 =&gt; v0.29.0\r\nsatria@teddy:~\/Documents\/projects\/go-restful-api$ go mod tidy<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>package controllers\r\n\r\nimport (\r\n\t\"errors\"\r\n\t\"net\/http\"\r\n\t\"advcha\/backend-api\/models\"\r\n\t\"github.com\/gin-gonic\/gin\"\r\n\t\"github.com\/go-playground\/validator\/v10\"\r\n)\r\n\r\n\/\/ ValidatePostInput struct is used to validate the input of the post\r\ntype ValidatePostInput struct {\r\n\tTitle string `json:\"title\" binding:\"required\"`\r\n\tContent string `json:\"content\" binding:\"required\"`\r\n}\r\n\r\n\/\/ ErrorMsg struct is used to return the error message\r\ntype ErrorMsg struct {\r\n\tField   string `json:\"field\"`\r\n\tMessage string `json:\"message\"`\r\n}\r\n\r\n\/\/ GetErrorMsg function is used to get the error message\r\nfunc GetErrorMsg(fe validator.FieldError) string {\r\n\tswitch fe.Tag() {\r\n\tcase \"required\":\r\n\t\treturn \"This field is required\"\r\n\t}\r\n\treturn \"Unknown error\"\r\n}\r\n\r\n\/\/ get all posts\r\nfunc FindPosts(c *gin.Context) {\r\n\t\/\/ get all posts from the database\r\n\tvar posts []models.Post\r\n\tmodels.DB.Find(&amp;posts)\r\n\r\n\t\/\/ return JSON response\r\n\tc.JSON(200, gin.H{\r\n\t\t\"status\": \"success\",\r\n\t\t\"message\": \"All posts retrieved successfully\",\r\n\t\t\"data\": posts,\r\n\t})\r\n}\r\n\r\nfunc InsertPost(c *gin.Context) {\r\n\t\/\/ validate the input\r\n\tvar input ValidatePostInput\r\n\r\n\tif err := c.ShouldBindJSON(&amp;input); err != nil {\r\n\t\tvar ve validator.ValidationErrors\r\n\t\tif errors.As(err, &amp;ve) {\r\n\t\t\tout := make([]ErrorMsg, len(ve))\r\n\t\t\tfor i, fe := range ve {\r\n\t\t\t\tout[i] = ErrorMsg{fe.Field(), GetErrorMsg(fe)}\r\n\t\t\t}\r\n\t\t\tc.AbortWithStatusJSON(http.StatusBadRequest, gin.H{\"error\": out})\r\n\t\t}\r\n\t\treturn\r\n\t}\r\n\r\n\t\/\/ create a new post\r\n\tpost := models.Post{Title: input.Title, Content: input.Content}\r\n\r\n\t\/\/ insert the new post into the database\r\n\tmodels.DB.Create(&amp;post)\r\n\r\n\t\/\/ return JSON response\r\n\tc.JSON(200, gin.H{\r\n\t\t\"status\": \"success\",\r\n\t\t\"message\": \"Post created successfully\",\r\n\t\t\"data\": post,\r\n\t})\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>2. Then add a route in main.go to insert the post like this<br \/>\n[codesyntax lang=&#8221;text&#8221;]<\/p>\n<pre>func main() {\r\n\t...\r\n\r\n\t\/\/ create a GET route with an endpoint \"\/posts\"\r\n\trouter.GET(\"\/api\/posts\", controllers.FindPosts)\r\n\r\n\t\/\/ create a POST route with an endpoint \"\/posts\"\r\n\trouter.POST(\"\/api\/posts\", controllers.InsertPost)\r\n\r\n\t\/\/ start the server with port 3000\r\n\trouter.Run(\":3000\") \/\/ listen and serve on\r\n}<\/pre>\n<p>[\/codesyntax]<\/p>\n<p>3. Run and test with Postman<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-12592\" src=\"http:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post.png\" alt=\"\" width=\"1247\" height=\"852\" srcset=\"https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post.png 1247w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post-300x205.png 300w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post-1024x700.png 1024w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post-768x525.png 768w, https:\/\/myprojects.advchaweb.com\/wp-content\/uploads\/2025\/01\/go-gin-restful-post-1200x820.png 1200w\" sizes=\"auto, (max-width: 709px) 85vw, (max-width: 909px) 67vw, (max-width: 1362px) 62vw, 840px\" \/><\/p>\n<p>Note: also need to test the validation with a json for empty title and content to make sure the validation is working.<br \/>\nthe above screen showed the json with title and content and the success result<br \/>\nthe output on http:\/\/localhost:3000\/api\/posts will be like this:<\/p>\n<pre>{\"data\":[{\"id\":1,\"title\":\"My First Post\",\"content\":\"Here is the content of my first post\"}],\"message\":\"All posts retrieved successfully\",\"status\":\"success\"}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>Ref: https:\/\/santrikoding.com\/tutorial-restful-api-golang-1-membuat-project-golang Note: Make sure golang is already installed by checking with &#8216;go version&#8217; on your linux terminal [codesyntax lang=&#8221;bash&#8221;] satria@teddy:~$ go version go version go1.18.3 linux\/amd64 [\/codesyntax] Note: it&#8217;ll be better to use the newest go version. I already installed go version 1.23.4 [codesyntax lang=&#8221;bash&#8221;] satria@teddy:~\/Downloads$ go version go version go1.23.4 linux\/amd64 [\/codesyntax] Note: &hellip; <a href=\"https:\/\/myprojects.advchaweb.com\/index.php\/2025\/01\/13\/golang-and-gin-restful-api\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Golang and Gin Restful API&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[45,128],"tags":[],"class_list":["post-12572","post","type-post","status-publish","format-standard","hentry","category-api-2","category-golang"],"_links":{"self":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/12572","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/comments?post=12572"}],"version-history":[{"count":18,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/12572\/revisions"}],"predecessor-version":[{"id":12593,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/posts\/12572\/revisions\/12593"}],"wp:attachment":[{"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/media?parent=12572"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/categories?post=12572"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/myprojects.advchaweb.com\/index.php\/wp-json\/wp\/v2\/tags?post=12572"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}