{"id":2513,"date":"2022-07-11T17:58:03","date_gmt":"2022-07-11T10:58:03","guid":{"rendered":"https:\/\/www.marketenterprise.vn\/blog\/?p=2513"},"modified":"2022-07-11T17:58:03","modified_gmt":"2022-07-11T10:58:03","slug":"rest-api-voi-golang-gin-minio","status":"publish","type":"post","link":"https:\/\/www.marketenterprise.vn\/blog\/rest-api-voi-golang-gin-minio.html","title":{"rendered":"REST API v\u1edbi Golang, Gin, MinIO v\u00e0 Docker"},"content":{"rendered":"<h2><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Golang, Gin<\/span><\/span><\/strong><\/h2>\n<h3><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Golang (Go)<\/span><\/span><\/strong><\/h3>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">a. Golang l\u00e0 g\u00ec?<\/span><\/span><\/span><\/em><\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-300x169.png\" alt=\"\" width=\"300\" height=\"169\" class=\"size-medium wp-image-2525 aligncenter\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-300x169.png 300w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-1024x578.png 1024w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-768x434.png 768w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-1536x867.png 1536w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8-1568x885.png 1568w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092915\/8.png 1576w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p class=\"p1\">Go \u0111\u01b0\u1ee3c Google ph\u00e1t tri\u1ec3n v\u00e0o n\u0103m 2007 cho c\u00e1c API v\u00e0 \u1ee9ng d\u1ee5ng web. Go g\u1ea7n \u0111\u00e2y \u0111\u00e3 tr\u1edf th\u00e0nh m\u1ed9t trong nh\u1eefng ng\u00f4n ng\u1eef l\u1eadp tr\u00ecnh ph\u00e1t tri\u1ec3n nhanh nh\u1ea5t do t\u00ednh \u0111\u01a1n gi\u1ea3n c\u0169ng nh\u01b0 kh\u1ea3 n\u0103ng x\u1eed l\u00fd c\u00e1c multi-core system, network v\u00e0 large codebase.<\/p>\n<p><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Go <\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">hay c\u00f2n g\u1ecdi l\u00e0 <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Golang <\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">ra \u0111\u1eddi nh\u1eb1m \u0111\u00e1p \u1ee9ng nhu c\u1ea7u c\u1ee7a c\u00e1c th\u00e0nh vi\u00ean l\u1eadp tr\u00ecnh trong c\u00e1c d\u1ef1 \u00e1n l\u1edbn. <\/span><span style=\"vertical-align: inherit;\">N\u00f3 \u0111\u00e3 tr\u1edf n\u00ean ph\u1ed5 bi\u1ebfn trong nhi\u1ec1u c\u00f4ng ty CNTT l\u1edbn nh\u1edd \u0111\u01a1n gi\u1ea3n c\u1ea5u tr\u00fac, hi\u1ec7n \u0111\u1ea1i v\u00e0 thu\u1ed9c t\u00ednh quen thu\u1ed9c v\u1ec1 c\u00fa ph\u00e1p. <\/span><span style=\"vertical-align: inherit;\">C\u00e1c c\u00f4ng ty s\u1eed d\u1ee5ng Go l\u00e0m ng\u00f4n ng\u1eef l\u1eadp tr\u00ecnh c\u1ee7a h\u1ecd bao g\u1ed3m <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Google<\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">, <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Uber<\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">, <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Twitch<\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">, <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Dropbox<\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">,&#8230;. Go c\u0169ng tr\u1edf n\u00ean ph\u1ed5 bi\u1ebfn trong gi\u1edbi khoa h\u1ecdc d\u1eef li\u1ec7u v\u00ec s\u1ef1 nhanh nh\u1eb9n v\u00e0 hi\u1ec7u su\u1ea5t c\u1ee7a n\u00f3.<\/span><\/span><\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">b. T\u1ea1i sao m\u00ecnh ch\u1ecdn Golang?<\/span><\/span><\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Tuy hi\u1ec7n t\u1ea1i Go kh\u00f4ng \u0111\u01b0\u1ee3c ph\u1ed5 bi\u1ebfn nh\u01b0 Java ho\u1eb7c Python, nh\u01b0ng c\u00e0ng ng\u00e0y Go c\u00e0ng \u0111\u01b0\u1ee3c nhi\u1ec1u ng\u01b0\u1eddi bi\u1ebft \u0111\u1ebfn h\u01a1n. <\/span><span style=\"vertical-align: inherit;\">N\u00f3 \u0111\u01b0\u1ee3c \u0111\u00e1nh gi\u00e1 l\u00e0 m\u1ed9t ng\u00f4n ng\u1eef t\u1ed1i gi\u1ea3n (<\/span><\/span><\/span>minimalist<span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">), d\u1ec5 h\u1ecdc, m\u00e3 minh b\u1ea1ch, t\u01b0\u01a1ng th\u00edch v\u00e0 nhanh.<\/span><\/span><\/span><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Hi\u1ec7n nay <b>Go <\/b>\u0111ang l\u00e0 <strong>top 3 ng\u00f4n ng\u1eef l\u1eadp tr\u00ecnh n\u00ean h\u1ecdc nh\u1ea5t<\/strong> v\u00e0 m\u1ee9c l\u01b0\u01a1ng trung b\u00ecnh cho m\u1ed9t Go Developer l\u00e0 <b>141,654$\/n\u0103m<\/b> theo <a href=\"https:\/\/www.simplilearn.com\/best-programming-languages-start-learning-today-article\" target=\"_blank\" rel=\"noopener\">simplilearn.com<\/a>. <\/span><\/span><\/span><i><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">(Ng\u00e0y 21\/06\/2022)<\/span><\/span><\/span><\/i><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">V\u00ec v\u1eady, m\u00ecnh quy\u1ebft \u0111\u1ecbnh l\u1ef1a ch\u1ecdn t\u00ecm hi\u1ec3u v\u1ec1 Golang.<\/span><\/span><\/span><\/p>\n<h3><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Gin<\/span><\/span><\/strong><\/h3>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">a. Gin l\u00e0 g\u00ec?<\/span><\/span><\/span><\/em><\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30093007\/9-213x300.png\" alt=\"\" width=\"213\" height=\"300\" class=\"aligncenter wp-image-2526 size-medium\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30093007\/9-213x300.png 213w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30093007\/9-728x1024.png 728w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30093007\/9-768x1080.png 768w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30093007\/9.png 1000w\" sizes=\"auto, (max-width: 213px) 100vw, 213px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">Gin (https:\/\/github.com\/gin-gonic\/gin) l\u00e0 m\u1ed9t framework nh\u1ecf v\u1edbi hi\u1ec7u n\u0103ng cao (high-performance micro-framework) c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng \u0111\u1ec3 x\u00e2y d\u1ef1ng c\u00e1c website v\u00e0 microservices. S\u1eed d\u1ee5ng Gin gi\u00fap cho vi\u1ec7c x\u00e2y d\u1ef1ng c\u00e1c lu\u1ed3ng x\u1eed l\u00fd request t\u1eeb c\u00e1c module c\u00f3 th\u1ec3 t\u00e1i s\u1eed d\u1ee5ng tr\u1edf n\u00ean \u0111\u01a1n gi\u1ea3n h\u01a1n r\u1ea5t nhi\u1ec1u. Gin th\u1ef1c hi\u1ec7n \u0111i\u1ec1u n\u00e0y b\u1eb1ng c\u00e1ch cho ph\u00e9p b\u1ea1n vi\u1ebft middleware c\u00f3 th\u1ec3 \u0111\u01b0\u1ee3c \u0111\u01b0a v\u00e0o m\u1ed9t ho\u1eb7c nhi\u1ec1u request handling ho\u1eb7c nh\u00f3m request handling. <\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\">b. T\u1ea1i sao m\u00ecnh ch\u1ecdn Gin?<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">Gin l\u00e0 m\u1ed9t trong nh\u1eefng framework h\u00e0ng \u0111\u1ea7u trong h\u1ec7 sinh th\u00e1i xoay quanh Go (Gin l\u00e0 web framework <\/span><b>top 1<\/b><span style=\"font-weight: 400;\"> c\u1ee7a ng\u00f4n ng\u1eef Go <\/span><a href=\"https:\/\/github.com\/mingrammer\/go-web-framework-stars\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">(C\u1eadp nh\u1eadp l\u1ea7n cu\u1ed1i 2021-10-03)<\/span><\/a><span style=\"font-weight: 400;\">). \u0110\u00e2y \u0111\u01b0\u1ee3c coi l\u00e0 m\u1ed9t minimalist framework v\u00ec n\u00f3 ch\u1ec9 bao g\u1ed3m c\u00e1c th\u01b0 vi\u1ec7n v\u00e0 t\u00ednh n\u0103ng c\u1ea7n thi\u1ebft nh\u1ea5t. \u0110i\u1ec1u n\u00e0y gi\u00fap Gin l\u00e0 l\u1ef1a ch\u1ecdn l\u00fd t\u01b0\u1edfng cho ng\u01b0\u1eddi m\u1edbi b\u1eaft \u0111\u1ea7u nh\u01b0 m\u00ecnh.<\/span><\/p>\n<h2><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">MinIO<\/span><\/span><\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">MinIO l\u00e0 m\u00e3 ngu\u1ed3n m\u1edf ph\u1ee5c v\u1ee5 vi\u1ec7c l\u01b0u tr\u1eef c\u00e1c object (Object Storage), t\u01b0\u01a1ng th\u00edch v\u1edbi Amazon S3, Kubernetes. MinIO \u0111\u01b0\u1ee3c thi\u1ebft k\u1ebf \u0111\u1ec3 ph\u1ee5c v\u1ee5 l\u01b0u tr\u1eef d\u1eef li\u1ec7u d\u1ea1ng object nh\u01b0 h\u00ecnh \u1ea3nh, video, file,\u2026<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Trong b\u00e0i vi\u1ebft n\u00e0y m\u00ecnh s\u1ebd s\u1eed d\u1ee5ng MinIO th\u00f4ng qua Docker v\u00e0 k\u1ebft n\u1ed1i v\u1edbi Gin nh\u01b0 m\u1ed9t c\u01a1 s\u1edf d\u1eef li\u1ec7u v\u1edbi t\u1eadp tin h\u1ecdc t\u1eadp.<\/span><\/span><\/span><\/p>\n<h2><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Docker<\/span><\/span><\/strong><\/h2>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">N\u00f3i ng\u1eafn g\u1ecdn <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Docker <\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">l\u00e0 m\u1ed9t n\u1ec1n t\u1ea3ng \u0111\u1ec3 gi\u00fap ph\u00e1t tri\u1ec3n, tri\u1ec3n khai v\u00e0 ch\u1ea1y \u1ee9ng d\u1ee5ng d\u1ec5 d\u00e0ng h\u01a1n b\u1eb1ng c\u00e1ch s\u1eed d\u1ee5ng c\u00e1c th\u00f9ng ch\u1ee9a (d\u1ef1a tr\u00ean n\u1ec1n t\u1ea3ng \u1ea3o h\u00f3a).<\/span><\/span><\/span><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u1ede b\u00e0i vi\u1ebft n\u00e0y m\u00ecnh s\u1ebd kh\u00f4ng \u0111i s\u00e2u v\u00e0o Docker. B\u1ea1n c\u00f3 th\u1ec3 tham kh\u1ea3o th\u00eam v\u1ec1 docker trong b\u00e0i vi\u1ebft<\/span><span style=\"vertical-align: inherit;\">\u00a0<\/span><\/span><\/span><a href=\"https:\/\/www.marketenterprise.vn\/blog\/docker-la-gi.html\"><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Docker l\u00e0 g\u00ec? <\/span><\/span><\/span><\/a>.<\/p>\n<h2><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Hi\u1ec7n Th\u1ef1c<\/span><\/span><\/strong><\/h2>\n<h3><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Vi\u1ebft ch\u01b0\u01a1ng tr\u00ecnh Hello World s\u1eed d\u1ee5ng Go<\/span><\/span><\/strong><\/h3>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u0110\u1ea7u ti\u00ean, nh\u01b0 l\u00e0 th\u01b0\u1eddng l\u1ec7, ch\u00fang ta s\u1ebd vi\u1ebft m\u1ed9t \u0111o\u1ea1n m\u00e3 nh\u1ecf b\u1eb1ng ch\u1eef Hello World. <\/span><span style=\"vertical-align: inherit;\">B\u1ea1n c\u00e0i \u0111\u1eb7t Golang theo h\u01b0\u1edbng d\u1eabn t\u1eeb trang ch\u1ee7 c\u1ee7a Go ( <\/span><\/span><\/span><a href=\"https:\/\/go.dev\/doc\/install\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">https:\/\/go.dev\/doc\/install<\/span><\/span><\/span><\/a><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"> ). <\/span><span style=\"vertical-align: inherit;\">Sau \u0111\u00f3 ch\u00fang ta s\u1ebd \u0111i qua c\u00e1c b\u01b0\u1edbc:<\/span><\/span><\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u00a0<u>B\u01b0\u1edbc 1<\/u>: T\u1ea1o th\u01b0 m\u1ee5c \u0111\u1ec3 ch\u1ee9a m\u00e3 ngu\u1ed3n c\u1ee7a d\u1ef1 \u00e1n Todo App<\/span><\/span><\/span><\/em><\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">mkdir go-rest-api<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 2<\/u>: <\/span><\/span><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Kh\u1edfi t\u1ea1o Go Modules<\/span><\/span><\/span><\/em><\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">go mod init TodoApp\r\ngo get -u github.com\/gin-gonic\/gin\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 3<\/u>: <\/span><\/span><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">T\u1ea1o t\u1ec7p main.go v\u00e0 vi\u1ebft \u0111\u1ea7u ti\u00ean ch\u01b0\u01a1ng tr\u00ecnh Hello World<\/span><\/span><\/span><\/em><\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package main\r\n  import (\r\n    \"fmt\"\r\n  )\r\nfunc main() {\r\n  fmt.Println(\"Hello World!\")\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 4<\/u>: <\/span><\/span><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Ch\u1ea1y file main.go s\u1eed d\u1ee5ng c\u00e2u l\u1ec7nh<\/span><\/span><\/span><\/em><\/h4>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">go run main.go<\/pre>\n<h4><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">B\u1ea1n s\u1ebd nh\u00ecn th\u1ea5y output nh\u01b0 sau:<\/span><\/span><\/span><\/h4>\n<p><b>Hello World!<\/b><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Nh\u01b0 v\u1eady l\u00e0 ch\u00fang ta \u0111\u00e3 ch\u1ea1y \u0111\u01b0\u1ee3c ch\u01b0\u01a1ng tr\u00ecnh \u0111\u1ea7u ti\u00ean \u0111\u01b0\u1ee3c s\u1eed d\u1ee5ng Go. <\/span><span style=\"vertical-align: inherit;\">Ti\u1ebfp theo m\u00ecnh s\u1ebd s\u1eed d\u1ee5ng Docker v\u00e0 Docker Compose \u0111\u1ec3 thi\u1ebft l\u1eadp m\u00f4i tr\u01b0\u1eddng ph\u00e1t tri\u1ec3n. <\/span><span style=\"vertical-align: inherit;\">Nh\u01b0 v\u1eady, nh\u1eefng ng\u01b0\u1eddi kh\u00e1c ho\u1eb7c ch\u00ednh b\u1ea1n sau n\u00e0y \u0111\u1ec1u c\u00f3 th\u1ec3 x\u00e2y d\u1ef1ng m\u00f4i tr\u01b0\u1eddng ch\u1ea1y d\u1ef1 \u00e1n ch\u1ec9 b\u1eb1ng m\u1ed9t c\u00e2u l\u1ec7nh <\/span><\/span><\/span><i><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u201cdocker-compile up\u201d<\/span><\/span><\/span><\/i><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"> m\u00e0 kh\u00f4ng c\u1ea7n quan t\u00e2m l\u00e0 \u1edf m\u00e1y ch\u00fang ta \u0111\u00e3 c\u00e0i \u0111\u1eb7t <\/span><\/span><\/span>Go hay ch\u01b0a<span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">. <\/span><span style=\"vertical-align: inherit;\">Ch\u00fang ta c\u00f9ng b\u1eaft \u0111\u1ea7u nh\u00e9.<\/span><\/span><\/span><\/p>\n<h3><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Thi\u1ebft l\u1eadp Docker<\/span><\/span><\/strong><\/h3>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u0110\u1ea7u ti\u00ean ch\u00fang ta h\u00e3y nh\u00ecn t\u1ed5ng quan v\u1ec1 d\u1ef1 \u00e1n ki\u1ebfn \u200b\u200btr\u00fac m\u00e0 ch\u00fang ta s\u1ebd th\u1ef1c hi\u1ec7n. Ki\u1ebfn tr\u00fac s\u1ebd nh\u01b0 sau<\/span><span style=\"vertical-align: inherit;\">:<\/span><\/span><\/span><\/p>\n<div id='gallery-1' class='gallery galleryid-2513 gallery-columns-3 gallery-size-full'><figure class='gallery-item'>\n\t\t\t<div class='gallery-icon landscape'>\n\t\t\t\t<a href=\"https:\/\/www.marketenterprise.vn\/blog\/rest-api-voi-golang-gin-minio.html\/nwbzyprxbzspmddscepb4iaw6dewu4mhksh2vqdd97bxzpttis8giznsjomt6y6bxr_0e10duskck3vs3jpwlvjl7mo5egsdmneai0fjfg0tomoivhx5jrzcv-rd\"><img loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"541\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30085513\/nwBZyPrxBzSpmDdScEpB4iaw6DeWu4mHKSH2vqdd97bxzpttis8gIZnSjomT6y6BXr_0e10Duskck3vs3JPWlVJL7Mo5EGsdMnEAI0fjfG0TOmOiVHx5jrzCv-rd.png\" class=\"attachment-full size-full\" alt=\"\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30085513\/nwBZyPrxBzSpmDdScEpB4iaw6DeWu4mHKSH2vqdd97bxzpttis8gIZnSjomT6y6BXr_0e10Duskck3vs3JPWlVJL7Mo5EGsdMnEAI0fjfG0TOmOiVHx5jrzCv-rd.png 731w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30085513\/nwBZyPrxBzSpmDdScEpB4iaw6DeWu4mHKSH2vqdd97bxzpttis8gIZnSjomT6y6BXr_0e10Duskck3vs3JPWlVJL7Mo5EGsdMnEAI0fjfG0TOmOiVHx5jrzCv-rd-300x222.png 300w\" sizes=\"auto, (max-width: 731px) 100vw, 731px\" \/><\/a>\n\t\t\t<\/div><\/figure>\n\t\t<\/div>\n\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">S\u1eed d\u1ee5ng Nginx l\u00e0m proxy ng\u01b0\u1ee3c: khi c\u00f3 y\u00eau c\u1ea7u g\u1ecdi v\u00e0o API, y\u00eau c\u1ea7u s\u1ebd chuy\u1ec3n v\u00e0o Nginx, sau \u0111\u00f3 \u0111\u01b0\u1ee3c chuy\u1ec3n ti\u1ebfp sang ph\u1ea7n ph\u1ee5 tr\u1ee3<\/span><\/span><\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Backend s\u1eed d\u1ee5ng khung Gin, t\u01b0\u01a1ng t\u00e1c v\u1edbi C\u01a1 s\u1edf d\u1eef li\u1ec7u s\u1eed d\u1ee5ng MinIO v\u00e0 tr\u1ea3 l\u1eddi ph\u1ea3n h\u1ed3i v\u1ec1 cho Nginx<\/span><\/span><\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">Nginx g\u1eedi ph\u1ea3n h\u1ed3i tr\u1ea3 v\u1ec1 cho ng\u01b0\u1eddi d\u00f9ng<\/span><\/span><\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">T\u1eeb ki\u1ebfn tr\u00fac n\u00e0y, ch\u00fang ta s\u1ebd c\u1ea5u tr\u00fac folder nh\u01b0 sau:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30090242\/TodoApp.png\" alt=\"\" width=\"179\" height=\"246\" class=\"aligncenter wp-image-2516 size-full\" \/><\/p>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 1<\/u>: T\u1ea1o <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">dockerfile <\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">cho backend trong TodoApp th\u01b0 m\u1ee5c <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\/ .docker \/ backend \/<\/span><\/span><\/b><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">T\u1eeb dockerfile n\u00e0y, sau qu\u00e1 tr\u00ecnh build ch\u00fang ta s\u1ebd c\u00f3 \u0111\u01b0\u1ee3c docker image cho backend. Ch\u1ea1y docker image n\u00e0y ch\u00fang ta s\u1ebd c\u00f3 container backend s\u1eb5n s\u00e0ng x\u1eed l\u00fd c\u00e1c request \u0111\u01b0\u1ee3c g\u1eedi \u0111\u1ebfn.<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">FROM golang:1.18.1-alpine3.15\r\n\r\nWORKDIR \/usr\/src\/app\r\nENV MINIO_SERVER_ACCESS_KEY=minioadmin\r\nENV MINIO_SERVER_SECRET_KEY=minioadmin\r\nCMD go run main.go\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 2<\/u>: T\u1ea1o t\u1ec7p nginx.conf trong TodoApp th\u01b0 m\u1ee5c <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\/ .docker \/ nginx \/<\/span><\/span><\/b><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">\u1ede file nginx.conf n\u00e0y, ch\u00fang ta s\u1ebd c\u1ea5u h\u00ecnh Nginx tr\u1edf th\u00e0nh m\u1ed9t reverse proxy.<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\"># Determine the formatting of the log that will be print to the access.log file\r\nlog_format testlog '$remote_addr - $remote_user [$time_local] '\r\n               '\"$request\" $status $bytes_sent '\r\n               '\"$http_referer\" $http_user_agent $request_body $gzip_ratio '\r\n               '\"$request_time $upstream_connect_time $upstream_header_time $upstream_response_time ';\r\n\r\n# Write the reverse proxy\r\nserver {\r\n    # Determine where to output the log\r\n    access_log \/var\/log\/nginx\/access.log;\r\n    # expose port 80\r\n    listen 80;\r\n\r\n    # if the root route get access it will return the default nginx html page\r\n    location \/api {\r\n        proxy_set_header X-Real-IP $remote_addr;\r\n        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\r\n        proxy_set_header Host $http_host;\r\n        proxy_set_header X-Forwarded-Proto $scheme;\r\n        # do not forget to include the scheme which is http\r\n        proxy_pass http:\/\/backend:8080;\r\n    }\r\n}\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"><u>B\u01b0\u1edbc 3<\/u>: T\u1ea1o t\u1eadp tin docker <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">&#8211; compos.yml <\/span><\/span><\/b><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">trong <\/span><\/span><\/span><b><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">TodoApp \/<\/span><\/span><\/b><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">S\u1eed d\u1ee5ng Docker Compose, ch\u00fang s\u1ebd s\u1ebd k\u1ebft n\u1ed1i c\u00e1c service l\u1ea1i theo ki\u1ebfn tr\u00fac nh\u01b0 \u0111\u00e3 chia s\u1ebb \u1edf tr\u00ean. T\u1eeb \u0111\u00f3, m\u1ed7i khi c\u1ea7n ch\u1ea1y d\u1ef1 \u00e1n, ch\u00fang ta ch\u1ec9 c\u1ea7n s\u1eed d\u1ee5ng l\u1ec7nh \u201cdocker-compose up\u201d l\u00e0 \u0111\u01b0\u1ee3c.\u00a0<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">version: '3.7'\r\nservices:\r\n    db:\r\n        image: 'bitnami\/minio:2022.4.16-debian-10-r9'\r\n        ports:\r\n            - '9002:9000'\r\n            - '9001:9001'\r\n        environment:\r\n            - MINIO_ROOT_USER=minioadmin\r\n            - MINIO_ROOT_PASSWORD=minioadmin\r\n        networks:\r\n            - TodoApp\r\n    backend:\r\n        build:\r\n            context: .\r\n            dockerfile: .\/.docker\/backend\/dockerfile\r\n        volumes:\r\n            - .\/backend:\/usr\/src\/app\r\n        depends_on:\r\n            - db\r\n        ports:\r\n            - 8080:8080\r\n        networks:\r\n            - TodoApp\r\n    nginx:\r\n        image: nginx:1.21.6-alpine\r\n        ports:\r\n            - 80:80\r\n        volumes:\r\n            - .\/.docker\/nginx\/nginx.conf:\/etc\/nginx\/conf.d\/default.conf\r\n        depends_on:\r\n            - backend\r\n        networks:\r\n            - TodoApp\r\nnetworks:\r\n    TodoApp:\r\n        driver: bridge\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><u>B\u01b0\u1edbc 4<\/u>: Chuy\u1ec3n <\/span><b>main.go, go.mod, go.sum<\/b><span style=\"font-weight: 400;\"> v\u00e0o th\u01b0 m\u1ef1c <\/span><b>TodoApp\/backend\/<\/b><\/em><\/h4>\n<h4><em><span style=\"font-weight: 400;\"><u>B\u01b0\u1edbc 5<\/u>: Ch\u1ea1y d\u1ef1 \u00e1n s\u1eed d\u1ee5ng c\u00e2u l\u1ec7nh<\/span><\/em><\/h4>\n<p><strong>docker-compose up<\/strong><\/p>\n<h4><em><span style=\"font-weight: 400;\"><u>B\u01b0\u1edbc 6<\/u>: B\u1ea1n s\u1ebd th\u1ea5y output nh\u01b0 sau<\/span><\/em><\/h4>\n<p><strong>Hello World!<\/strong><\/p>\n<ol><\/ol>\n<h3><strong>Thi\u1ebft l\u1eadp Route<\/strong><\/h3>\n<h4><em><span style=\"font-weight: 400;\">a. Route l\u00e0 g\u00ec<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">Route t\u1ea1m d\u1ecbch l\u00e0 m\u1ed9t tuy\u1ebfn \u0111\u01b0\u1eddng. N\u00f3 s\u1ebd th\u1ef1c hi\u1ec7n nhi\u1ec7m v\u1ee5 k\u1ebft n\u1ed1i gi\u1eefa client v\u00e0 server.<\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\">b. T\u1ea1i sao ph\u1ea3i d\u00f9ng Route?<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">Route lu\u00f4n l\u00e0 m\u1ed9t ph\u1ea7n quan tr\u1ecdng c\u1ee7a h\u1ec7 th\u1ed1ng website. T\u1ea5t c\u1ea3 c\u00e1c request khi qua Route \u0111\u1ec1u \u0111\u01b0\u1ee3c ki\u1ec3m tra v\u00e0 x\u1eed l\u00fd. S\u1eed d\u1ee5ng h\u1ec7 th\u1ed1ng \u0111\u1ecbnh tuy\u1ebfn cho ph\u00e9p ch\u00fang ta c\u1ea5u tr\u00fac \u1ee9ng d\u1ee5ng c\u1ee7a m\u00ecnh theo c\u00e1ch t\u1ed1t h\u01a1n v\u00e0 t\u01b0\u1eddng minh h\u01a1n.<\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\">c. T\u1ea1o router<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">C\u00e1ch m\u1eb7c \u0111\u1ecbnh \u0111\u1ec3 t\u1ea1o m\u1ed9t Route trong Gin nh\u01b0 sau:<\/span><\/p>\n<p><b>router := gin.Default()<\/b><\/p>\n<p><b>router.GET(&#8220;\/api\/todos&#8221;, func(c *gin.Context) {<\/b><\/p>\n<p><b>c.JSON(http.StatusOK, gin.H{<\/b><\/p>\n<p><b>&#8220;message&#8221;: &#8220;Hello World!&#8221;,<\/b><\/p>\n<p><b>})<\/b><\/p>\n<p><span style=\"font-weight: 400;\">File main.go l\u00fac n\u00e0y s\u1ebd nh\u01b0 sau:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package main\r\n\r\nimport (\r\n    \"net\/http\"\r\n    \"time\"\r\n    \"github.com\/gin-gonic\/gin\"\r\n)\r\n\r\nfunc main() {\r\n    time.Sleep(3 * time.Second)\r\n    router := gin.Default()\r\n    router.GET(\"\/api\/todos\", func(c *gin.Context) {\r\n            c.JSON(http.StatusOK, gin.H{\r\n                \"message\": \"Hello World!\",\r\n        })\r\n    })\r\n    router.Run(\":8080\")\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">Ch\u1ea1y l\u1ec7nh<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Truy c\u1eadp url: <\/span><a href=\"http:\/\/localhost:8080\/api\/todos\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">localhost:8080\/api\/todos\/<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400;\">K\u1ebft qu\u1ea3 s\u1ebd gi\u1ed1ng nh\u01b0 sau:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30091138\/1-300x164.png\" alt=\"\" width=\"300\" height=\"164\" class=\"size-medium wp-image-2517 aligncenter\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30091138\/1-300x164.png 300w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30091138\/1.png 359w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">V\u1eady l\u00e0 ch\u00fang ta \u0111\u00e3 v\u1eeba t\u1ea1o th\u00e0nh c\u00f4ng m\u1ed9t route \u0111\u1ec3 x\u1eed l\u00fd request s\u1eed d\u1ee5ng Gin. Hi\u1ec7n t\u1ea1i, m\u1ed7i khi ng\u01b0\u1eddi d\u00f9ng g\u1ecdi v\u00e0o API \/api\/todos th\u00ec s\u1ebd nh\u1eadn \u0111\u01b0\u1ee3c response l\u00e0 { \u201cmessage\u201d: \u201cHello World\u201d }. \u1ede ph\u1ea7n ti\u1ebfp theo ch\u00fang ta s\u1ebd c\u00f9ng nhau ho\u00e0n thi\u1ec7n m\u1ed9t API ho\u00e0n ch\u1ec9nh cho vi\u1ec7c qu\u1ea3n l\u00fd c\u00e1c Todo.<\/span><\/p>\n<h3><strong>Todo Model<\/strong><\/h3>\n<h4><em><span style=\"font-weight: 400;\">a. \u0110\u1ea7u ti\u00ean ch\u00fang ta c\u1ea7n m\u00f4 h\u00ecnh h\u00f3a m\u1ed9t Todo.<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">Thu\u1ed9c t\u00ednh c\u1ee7a m\u1ed9t todo g\u1ed3m:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">+Id string<\/span><\/p>\n<p><span style=\"font-weight: 400;\">+Name string<\/span><\/p>\n<p><span style=\"font-weight: 400;\">(Note: <\/span><b>T\u00ean thu\u1ed9c t\u00ednh ph\u1ea3i vi\u1ebft hoa ch\u1eef c\u00e1i \u0111\u1ea7u<\/b><span style=\"font-weight: 400;\">. N\u1ebfu kh\u00f4ng s\u1ebd b\u1ecb l\u1ed7i)<\/span><\/p>\n<h4><em><span style=\"font-weight: 400;\">b. T\u1ea1o file JSON<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">M\u00ecnh s\u1ebd s\u1eed d\u1ee5ng MinIO nh\u01b0 m\u1ed9t Database n\u00ean nh\u1eefng trao \u0111\u1ed5i d\u1eef li\u1ec7u gi\u1eefa <\/span><b>Server<\/b><span style=\"font-weight: 400;\"> v\u00e0 <\/span><b>Database<\/b><span style=\"font-weight: 400;\"> s\u1ebd l\u00e0 <\/span><b>file json.\u00a0<\/b><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">func CreateJson(id, name string) (jsonData []byte, todo Todo){\r\n    todo = Todo{\r\n        Id: id, Name: name,\r\n    }\r\n    jsonData, err :=json.Marshal(todo)\r\n    if err != nil {\r\n        log.Fatal(err)\r\n    }\r\n    return jsonData, todo\r\n}\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\">\u00a0c. L\u1ea5y t\u1ea5t c\u1ea3 d\u1eef li\u1ec7u Todo<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">V\u00ec ch\u00fang ta giao ti\u1ebfp v\u1edbi database b\u1eb1ng d\u1eef li\u1ec7u json. N\u00ean \u0111\u1ec3 nh\u1eadn \u0111\u01b0\u1ee3c d\u1eef li\u1ec7u theo c\u1ea5u tr\u00fac Todo. Ch\u00fang ta ph\u1ea3i chuy\u1ec3n \u0111\u1ed5i d\u1eef li\u1ec7u.<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">func GetAllTodos(jsonFiles []io.Reader) (temp TodoList){\r\n    for i:=0; i &lt; len(jsonFiles); i++{\r\n        data := StreamToByte(jsonFiles[i])\r\n        var todo Todo\r\n        json.Unmarshal(data, &amp;todo)\r\n        temp.TodoList = append(temp.TodoList, todo)\r\n    }\r\n    return temp\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">L\u00fac n\u00e0y ta s\u1ebd c\u00f3 file <\/span><b>Todo.go<\/b><span style=\"font-weight: 400;\"> \u1edf th\u01b0 m\u1ee5c <\/span><b>TodoApp\/backend\/Models nh\u01b0 sau:<\/b><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package models\r\n\r\nimport (\r\n    \"bytes\"\r\n    \"encoding\/json\"\r\n    \"io\"\r\n    \"log\"\r\n)\r\ntype TodoList struct{\r\n \tTodoList []Todo `json:\"TodoList\"`\r\n}\r\ntype Todo struct {\r\n    Id string `json:\"Id\"`\r\n    Name string `json:\"Name\"`\"\r\n}\r\n\r\nfunc CreateJson(id, name string) (jsonData []byte, todo Todo){\r\n    todo = Todo{\r\n        Id: id, Name: name,\r\n    }\r\n    jsonData, err :=json.Marshal(todo)\r\n    if err != nil {\r\n        log.Fatal(err)\r\n    }\r\n    return jsonData, todo\r\n}\r\n\r\nfunc StreamToByte(stream io.Reader) []byte {\r\n    buf := new(bytes.Buffer)\r\n      buf.ReadFrom(stream)\r\n      return buf.Bytes()\r\n  }\r\nfunc GetATodo(jsonFile io.Reader) (temp Todo){\r\n    data := StreamToByte(jsonFile)\r\n    json.Unmarshal(data, &amp;temp)\r\n    return temp\r\n}\r\nfunc GetAllTodos(jsonFiles []io.Reader) (temp TodoList){\r\n    for i:=0; i &lt; len(jsonFiles); i++{\r\n        data := StreamToByte(jsonFiles[i])\r\n        var todo Todo\r\n        json.Unmarshal(data, &amp;todo)\r\n        temp.TodoList = append(temp.TodoList, todo)\r\n    }\r\n    return temp\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">Nh\u01b0 v\u1eady l\u00e0 ch\u00fang ta \u0111\u00e3 c\u00f3 m\u1ed9t Model c\u01a1 b\u1ea3n. Ti\u1ebfp theo ch\u00fang ta c\u1ea7n m\u1ed9t c\u1ea7u n\u1ed1i gi\u1eefa MinIO v\u00e0 Backend c\u1ee7a ch\u00fang ta. Th\u00f4ng th\u01b0\u1eddng, n\u1ebfu nh\u01b0 s\u1eed d\u1ee5ng c\u00e1c framework nh\u01b0 PHP Laravel v\u1edbi h\u1ec7 c\u01a1 s\u1edf d\u1eef li\u1ec7u l\u00e0 MySQL, Postgre,&#8230; framework s\u1ebd cung c\u1ea5p s\u1eb5n c\u00e1c connector cho ch\u00fang ta config v\u00e0 s\u1eed d\u1ee5ng. \u1ede \u0111\u00e2y m\u00ecnh s\u1ebd vi\u1ebft m\u1ed9t connector \u0111\u01a1n gi\u1ea3n \u0111\u1ec3 giao ti\u1ebfp v\u1edbi MinIO.\u00a0\u00a0<\/span><\/p>\n<h3><strong>Database connector<\/strong><\/h3>\n<p><span style=\"font-weight: 400;\">V\u00ec \u0111\u00e2y l\u00e0 m\u1ed9t connector \u0111\u01a1n gi\u1ea3n n\u00ean m\u00ecnh s\u1ebd hard-coded accessKeyID, <\/span><span style=\"font-weight: 400;\">secretAccessKey,..<\/span><span style=\"font-weight: 400;\">. Th\u00f4ng th\u01b0\u1eddng nh\u1eefng th\u00f4ng tin n\u00e0y n\u00ean s\u1eed d\u1ee5ng bi\u1ebfn m\u00f4i tr\u01b0\u1eddng \u0111\u1ec3 l\u01b0u tr\u1eef v\u00e0 code c\u1ee7a ch\u00fang ta s\u1ebd \u0111\u1ecdc t\u1eeb bi\u1ebfn m\u00f4i tr\u01b0\u1eddng \u0111\u1ec3 config.<\/span> <span style=\"font-weight: 400;\">File <\/span><b>MinIODB.go<\/b><span style=\"font-weight: 400;\"> trong th\u01b0 m\u1ee5c <\/span><b>TodoApp\/backend\/Database\/ <\/b><span style=\"font-weight: 400;\">s\u1ebd nh\u01b0 sau:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package Config\r\n\r\nimport (\r\n    \"context\"\r\n    \"fmt\"\r\n    \"io\"\r\n    \"log\"\r\n    \"github.com\/minio\/minio-go\/v7\"\r\n    \"github.com\/minio\/minio-go\/v7\/pkg\/credentials\"\r\n    \"github.com\/sirupsen\/logrus\"\r\n)\r\nconst endpoint = \"db:9000\"\r\nconst accessKeyID = \"minioadmin\"\r\nconst secretAccessKey = \"minioadmin\"\r\n\/\/Create connect\r\nfunc ConnectDB()(c *minio.Client,err error){\r\n    useSSL := false\r\n    minioClient, err := minio.New(endpoint, &amp;minio.Options{\r\n        Creds:  credentials.NewStaticV4(accessKeyID, secretAccessKey, \"\"),\r\n        Secure: useSSL,\r\n    })\r\n    if err != nil {\r\n        log.Fatalln(err)\r\n    }\r\n    return minioClient, err\r\n}\r\n\/\/Set permission\r\nfunc SetPermission(client *minio.Client, bucketName string) error{\r\n    policy := `{\"Version\": \"2012-10-17\",\"Statement\": [{\"Action\": [\"s3:GetObject\"],\"Effect\": \"Allow\",\"Principal\": {\"AWS\": [\"*\"]},\"Resource\": [\"arn:aws:s3:::`+ bucketName +`\/*\"],\"Sid\": \"\"}]}`\r\n\r\n    err := client.SetBucketPolicy(context.Background(), bucketName, policy)\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        return err\r\n    }\r\n    return err\r\n}\r\n\/\/Create bucket\r\nfunc CreateBucket(client *minio.Client, bucketName string) error{\r\n    ctx := context.Background()\r\n    err := client.MakeBucket(ctx, bucketName, minio.MakeBucketOptions{Region: \"ap-northeast-1\"})\r\n    if err != nil{\r\n        exists, errBucketExists :=client.BucketExists(ctx, bucketName)\r\n        if errBucketExists != nil {\r\n            logrus.Errorf(\"[UploadImage] check bucket exists error: %s\", err)\r\n            return err\r\n        }\r\n        if !exists {\r\n            logrus.Errorf(\"[UploadImage] make bucket error: %s\", err)\r\n            return err\r\n        }\r\n    }\r\n    return err\r\n}\r\n\/\/Upload data to MinIO\r\nfunc UploadData(client *minio.Client, bucketName, objectName string, data io.Reader) error {\r\n    _, err := client.GetBucketPolicy(context.Background(), bucketName)\r\n    if err != nil {\r\n        log.Fatalln(err)\r\n    }\r\n    n, err := client.PutObject(context.Background(), bucketName, objectName, data, -1, minio.PutObjectOptions{ContentType: \"application\/octet-stream\"})\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        return err\r\n    }\r\n    fmt.Println(\"Successfully uploaded bytes: \", n)\r\n    return err\r\n}\r\n\/\/Get a data from MinIO\r\nfunc GetDataTodo(client *minio.Client, bucketName, objectName string) (file io.Reader) {\r\n    _, err := client.GetBucketPolicy(context.Background(), bucketName)\r\n    if err != nil {\r\n        log.Fatalln(err)\r\n    }\r\n    file, err = client.GetObject(context.Background(), bucketName, objectName, minio.GetObjectOptions{})\r\n    if err != nil {\r\n        fmt.Println(err)\r\n        return \r\n    }\r\n    return file\r\n}\r\n\/\/Get all data from MinIO\r\nfunc GetDataTodoList(client *minio.Client, bucketName string) (file []io.Reader) {\r\n    _, err := client.GetBucketPolicy(context.Background(), bucketName)\r\n    if err != nil {\r\n        log.Fatalln(err)\r\n    }\r\n    objectCh := client.ListObjects(context.Background(), bucketName, minio.ListObjectsOptions{\r\n        Recursive: true,\r\n \t})\r\n     for object := range objectCh {\r\n        file = append(file, GetDataTodo(client, bucketName, object.Key))\r\n    }\r\n    return file\r\n}\r\n<\/pre>\n<h3><strong>Controllers<\/strong><\/h3>\n<p><span style=\"font-weight: 400;\">Cu\u1ed1i c\u00f9ng ch\u00fang ta s\u1ebd t\u1ea1o ra file controller th\u1ef1c hi\u1ec7n nhi\u1ec7m v\u1ee5 li\u00ean k\u1ebft gi\u1eefa server \u0111\u01b0\u1ee3c x\u00e2y d\u1ef1ng b\u1eb1ng Go v\u00e0 database MinIO.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">File <\/span><b>TodoController.go<\/b><span style=\"font-weight: 400;\"> trong th\u01b0 m\u1ee5c <\/span><b>TodoApp\/backend\/http\/Controllers\/ <\/b><span style=\"font-weight: 400;\">s\u1ebd nh\u01b0 sau:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package Controllers\r\n\r\nimport (\r\n    \"TodoApp\/Database\"\r\n    \"TodoApp\/models\"\r\n    \"bytes\"\r\n    \"github.com\/minio\/minio-go\/v7\"\r\n)\r\n\r\nfunc GetAllTodos(Client *minio.Client, bucketName string) (res models.TodoList) {\r\n    todoList := Config.GetDataTodoList(Client, bucketName)\r\n    res = models.GetAllTodos(todoList)\r\n    return res\r\n}\r\n\r\nfunc AddTodo(Client *minio.Client, bucketName, objectName, id, name string)(res models.Todo){\r\n    jsonData,res := models.CreateJson(id, name)\r\n    data := bytes.NewReader(jsonData)\r\n    err := Config.UploadData(Client, bucketName,objectName, data)\r\n    if err !=nil{\r\n        panic(err)\r\n    }\r\n    return res\r\n}\r\n\r\nfunc UploadJson(Client *minio.Client, bucketName, objectName, id, name string){\r\n    jsonFile,_:=models.CreateJson(id, name)\r\n    data := bytes.NewReader(jsonFile)\r\n    err := Config.UploadData(Client, bucketName,objectName, data)\r\n    if err !=nil{\r\n        panic(err)\r\n    }\r\n}\r\n<\/pre>\n<ol><\/ol>\n<h3><strong>Update file main.go<\/strong><\/h3>\n<p><span style=\"font-weight: 400;\">D\u1eef li\u1ec7u example s\u1ebd \u0111\u01b0\u1ee3c upload l\u00ean MinIO \u0111\u1ec3 tr\u1ef1c quan h\u01a1n.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">File main.go l\u00fac n\u00e0y s\u1ebd nh\u01b0 sau:<\/span><\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">package main\r\n\r\nimport (\r\n    \"TodoApp\/Database\"\r\n    \"TodoApp\/http\/Controllers\"\r\n    \"TodoApp\/models\"\r\n    \"log\"\r\n    \"time\"\r\n    \"github.com\/gin-gonic\/gin\"\r\n)\r\n\r\nfunc main() {\r\n    time.Sleep(3 * time.Second)\r\n    Client, err := Config.ConnectDB()\r\n    if err != nil {\r\n        log.Println(err)\r\n    }\r\n    err = Config.CreateBucket(Client, \"todolist\")\r\n    if err != nil {\r\n        log.Println(err)\r\n    }\r\n    \/\/example data\r\n    Controllers.UploadJson(Client, \"todolist\",\"todo1.json\",\"1\",\"go to school\")\r\n    Controllers.UploadJson(Client, \"todolist\",\"todo2.json\",\"2\",\"go to canteen\")\r\n    Controllers.UploadJson(Client, \"todolist\",\"todo3.json\",\"3\",\"come back home\")\r\n    \/\/route\r\n    router := gin.Default()\r\n    router.GET(\"\/api\/todos\", func(c *gin.Context) {\r\n        ab := Controllers.GetAllTodos(Client, \"todolist\")\r\n        c.JSON(200, ab)\r\n        })\r\n    router.POST(\"\/api\/todos\/:uid\/:id\", func(c *gin.Context) {\r\n        var todo models.Todo\r\n        err := c.BindJSON(&amp;todo)\r\n        if err != nil {\r\n            log.Fatal(err)\r\n        }\r\n        res := Controllers.AddTodo(Client, \"todolist\", c.Param(\"id\")+\".json\", c.Param(\"id\"), todo.Name)\r\n        c.JSON(200, res)\r\n    })\r\n    router.Run(\":8080\")\r\n}\r\n<\/pre>\n<h4><em><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">a. C\u1ea5u tr\u00fac th\u01b0 m\u1ee5c:<\/span><\/span><\/span><\/em><\/h4>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092028\/2-176x300.png\" alt=\"\" width=\"176\" height=\"300\" class=\"size-medium wp-image-2518 aligncenter\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092028\/2-176x300.png 176w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092028\/2.png 224w\" sizes=\"auto, (max-width: 176px) 100vw, 176px\" \/><\/p>\n<h4><em><span style=\"font-weight: 400;\">b. Ch\u1ea1y l\u1ec7nh <\/span><\/em><\/h4>\n<p><b>docker-compose up<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Truy c\u1eadp url: <\/span><a href=\"http:\/\/localhost:8080\/api\/todos\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">localhost:8080\/api\/todos\/<\/span><\/a><\/p>\n<p><span style=\"font-weight: 400;\">K\u1ebft qu\u1ea3 s\u1ebd nh\u01b0 sau:<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\"><br \/>\n<img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092203\/3-207x300.png\" alt=\"\" width=\"207\" height=\"300\" class=\"size-medium wp-image-2519 aligncenter\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092203\/3-207x300.png 207w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092203\/3.png 345w\" sizes=\"auto, (max-width: 207px) 100vw, 207px\" \/><\/span><\/span><\/span><\/p>\n<p><span style=\"font-weight: 400;\">Th\u00eam m\u1ed9t Todo b\u1eb1ng ph\u01b0\u01a1ng th\u1ee9c POST qua URL: <\/span><span style=\"font-weight: 400;\"><br \/>\n<\/span><b>localhost:8080\/api\/todos\/ +id<\/b><\/p>\n<p><span style=\"font-weight: 400;\">M\u00ecnh d\u00f9ng extension: Thunder Client tr\u00ean Visual Studio \u0111\u1ec3 test.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">K\u1ebft qu\u1ea3:<\/span><\/p>\n<p><span style=\"font-weight: 400;\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092310\/4-1024x444.png\" alt=\"\" width=\"1024\" height=\"444\" class=\"aligncenter wp-image-2520 size-large\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092310\/4-1024x444.png 1024w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092310\/4-300x130.png 300w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092310\/4-768x333.png 768w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092310\/4.png 1058w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/span><\/p>\n<p><span style=\"font-weight: 400;\"><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">\u00a0<\/span><\/span><\/span><\/p>\n<p><span style=\"font-weight: 400;\">Truy c\u1eadp l\u1ea1i url: <\/span><a href=\"http:\/\/localhost:8080\/api\/todos\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">localhost:8080\/api\/todos\/<\/span><\/a><span style=\"font-weight: 400;\">, danh s\u00e1ch Todolist \u0111\u00e3 c\u00f3 th\u00eam Todo m\u00e0 ch\u00fang ta v\u1eeba t\u1ea1o b\u1eb1ng POST request.<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092411\/5-175x300.png\" alt=\"\" width=\"175\" height=\"300\" class=\"aligncenter wp-image-2521 size-medium\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092411\/5-175x300.png 175w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092411\/5.png 346w\" sizes=\"auto, (max-width: 175px) 100vw, 175px\" \/><\/p>\n<ol><\/ol>\n<h4><em><span style=\"font-weight: 400;\">c. Truy c\u1eadp <\/span><a href=\"http:\/\/localhost:9001\/login\" target=\"_blank\" rel=\"noopener\"><b>localhost:9001<\/b><\/a><span style=\"font-weight: 400;\"> \u0111\u1ec3 xem d\u1eef li\u1ec7u trong MinIO<\/span><\/em><\/h4>\n<p><span style=\"font-weight: 400;\">\u0110\u0103ng nh\u1eadp v\u1edbi <\/span><b>Username<\/b><span style=\"font-weight: 400;\"> v\u00e0 <\/span><b>Password<\/b><span style=\"font-weight: 400;\">: <\/span><b>minioadmin<\/b><\/p>\n<p><span style=\"font-weight: 400;\">Truy c\u1eadp v\u00e0o bucket <\/span><b>todolist<\/b><span style=\"font-weight: 400;\"> ch\u00fang ta s\u1ebd s\u1ebd nh\u00ecn th\u1ea5y nh\u01b0 th\u1ebf n\u00e0y:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-1024x356.png\" alt=\"\" width=\"1024\" height=\"356\" class=\"aligncenter wp-image-2522 size-large\" srcset=\"https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-1024x356.png 1024w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-300x104.png 300w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-768x267.png 768w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-1536x535.png 1536w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6-1568x546.png 1568w, https:\/\/mevn-public.s3-ap-southeast-1.amazonaws.com\/marketenterprise.vn\/wp-images\/2022\/06\/30092515\/6.png 1600w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h2><strong><span style=\"vertical-align: inherit;\"><span style=\"vertical-align: inherit;\">K\u1ebft lu\u1eadn<\/span><\/span><\/strong><\/h2>\n<p><span style=\"font-weight: 400;\">V\u1eady l\u00e0 m\u00ecnh \u0111\u00e3 c\u00f9ng c\u00e1c b\u1ea1n th\u1ef1c hi\u1ec7n t\u1ea1o REST API TodoApp b\u1eb1ng Golang Gin, MinIO v\u00e0 Docker. Qua b\u00e0i vi\u1ebft n\u00e0y, c\u00e1c b\u1ea1n \u0111\u00e3 c\u00f3 m\u1ed9t b\u01b0\u1edbc kh\u1edfi \u0111\u1ea7u \u0111\u1ec3 t\u1ef1 m\u00ecnh b\u01b0\u1edbc ti\u1ebfp tr\u00ean con \u0111\u01b0\u1eddng tr\u1edf th\u00e0nh Go Developer.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Hy v\u1ecdng b\u00e0i vi\u1ebft s\u1ebd h\u1eefu \u00edch cho nh\u1eefng b\u1ea1n m\u1edbi ti\u1ebfp c\u1eadn v\u1edbi Golang nh\u01b0 m\u00ecnh. Nh\u00ecn chung, m\u00ecnh th\u1ea5y kh\u00e1 h\u1ee9ng th\u00fa khi \u0111\u1ebfn v\u1edbi Golang. V\u00e0 kh\u00f4ng h\u1ec1 h\u1ed1i h\u1eadn v\u1edbi th\u1eddi gian m\u00ecnh b\u1ecf ra, v\u00ec n\u00f3 r\u1ea5t nhanh v\u00e0 d\u1ec5 ti\u1ebfp c\u1eadn. C\u00e1m \u01a1n v\u00ec \u0111\u00e3 d\u00e0nh th\u1eddi gian xem b\u00e0i vi\u1ebft c\u1ee7a m\u00ecnh.<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Trong m\u1ed9t l\u1ea7n tham gia d\u1ef1 \u00e1n, m\u00ecnh ph\u1ea3i g\u1eb7p nhi\u1ec1u h\u1ea1n ch\u1ebf c\u1ee7a ch\u01b0\u01a1ng tr\u00ecnh l\u1eadp tr\u00ecnh ng\u00f4n ng\u1eef m\u00e0 m\u00ecnh \u0111ang s\u1eed d\u1ee5ng, khi t\u00ecm hi\u1ec3u v\u1ec1 gi\u1ea3i ph\u00e1p kh\u1eafc ph\u1ee5c, m\u00ecnh t\u00ecm th\u1ea5y Golang nh\u01b0 m\u1ed9t v\u1ecb c\u1ee9u tinh \u1edf th\u1eddi \u0111i\u1ec3m \u0111\u00f3. Sau m\u1ed9t th\u1eddi gian ng\u1eafn t\u00ecm hi\u1ec3u v\u1ec1 Go, t\u1eeb g\u00f3c nh\u00ecn c\u1ee7a m\u1ed9t ng\u01b0\u1eddi m\u1edbi ti\u1ebfp c\u1eadn, m\u00ecnh &#8220;nh\u00ecn th\u1ea5y&#8221; m\u1ed9t s\u1ed1 \u01b0u \u0111i\u1ec3m khi\u1ebfn Golang l\u00e0 ng\u00f4n ng\u1eef l\u1eadp tr\u00ecnh ti\u1ebfp theo m\u00e0 m\u00ecnh s\u1ebd t\u00ecm hi\u1ec3u v\u00e0 s\u1eed d\u1ee5ng.<\/p>\n<p>Trong b\u00e0i vi\u1ebft n\u00e0y m\u00ecnh s\u1ebd h\u01b0\u1edbng d\u1eabn t\u1eebng b\u01b0\u1edbc th\u1ef1c hi\u1ec7n REST API TODO App v\u1edbi Golang Gin, MinIO (S3 compatible object storage) v\u00e0 Docker.<\/p>\n","protected":false},"author":39,"featured_media":2524,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[105,106],"class_list":["post-2513","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology","tag-go","tag-golang"],"_links":{"self":[{"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/posts\/2513","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/users\/39"}],"replies":[{"embeddable":true,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/comments?post=2513"}],"version-history":[{"count":0,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/posts\/2513\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/media\/2524"}],"wp:attachment":[{"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/media?parent=2513"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/categories?post=2513"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.marketenterprise.vn\/blog\/wp-json\/wp\/v2\/tags?post=2513"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}