src
میتوانید یک فولدر خاص برای این پروژه ایجاد کنید یا برای ساماندهی بیشتر پروژههای مختلف یک پوشه با نام github.com
ایجاد کنید و در آن پوشهی دیگری ایجاد کنید و نام آن را همان نام کاربری خود در GitHub قرار دهید. در نهایت در مسیر GOPATH/src/github.com/<Github username>
یک پوشهی جدید برای پروژهی فعلی با نام دلخواه ایجاد کنید.برای پیادهسازی ساختار اولیهی پروژه میتوانید به شکل زیر عمل کنید:
mkdir go-rest-api cd go-rest-api touch main.go
پس از ایجاد کردن فایل main.go
از یک ویرایشگر کد برای توسعهی برنامه کمک میگیریم و کدهای زیر را در فایل ایجاد شده قرار میدهیم:
package main import "fmt" func main() { fmt.Println("Hello World!") }
برای کامپایل این برنامه ساده میتوانید در Terminal فعلی دستور go build
را اجرا کرده و درنهایت به شکل زیر برنامهی کامپایل شده را اجرا کنید:
./go-rest-api
انتظار میرود که خروجی زیر در Terminal شما چاپ شود:
Hello World!
Gorilla Mux یک پکیج است که به شما امکان میدهد routeهای مورد نیاز برنامه را ایجاد کرده و هر کدام از درخواستهای ورودی را به Controller مربوطه ارجاع دهید. قبل از کار با پکیج Mux باید آن را به شکل زیر نصب کرده:
go mod init go get -u github.com/gorilla/mux
و در مرحلهی بعد اولین endpoint برنامه را تعریف کنیم:
package main import ( "fmt" "log" "net/http" "github.com/gorilla/mux" ) func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) log.Fatal(http.ListenAndServe(":8080", router)) }
مطمئنا پس از ایجاد هر تغییری در کدها باید برنامه را مجددا اجرا کنید. حال برای اجرای برنامه دو راه حل وجود دارد که یکی از آنها کامپایل برنامه و اجرای برنامهی کامپایل شده است اما برای سریعتر شدن فرایند تست برنامه میتوانید دستور go run main.go
را اجرا کنید که بدون نیاز به کامپایل، سرور توسعه داده شده را برای شما اجرا میکند.
خروجی مورد انتظار پس از راهاندازی و ارسال درخواست GET به برنامه در آدرس localhost:8080 به شکل زیر است.
برای شبیهسازی دیتابیس میتوانیم رویدادها را به شکل زیر در برنامه تعریف کنیم:
type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, }
در این ساختار فقط از ID
، Title
و Description
برای ذخیرهی رویدادها استفاده کردهایم و در ادامه کدهای مربوط به اضافه کردن، بهروزرسانی و حذف رویدادها را پیادهسازی خواهیم کرد.
برای ایجاد یک رویداد جدید باید دادههای ارسال شده بهصورت POST
را دریافت کرده و به دیتابیس شبیهسازی شده اضافه کنیم. در مرحلهی بعد پس از اضافه شدن موفقیتآمیز رویداد به دیتابیس شبیهسازی شده، همان رویداد را با status code شمارهی 201
به کاربر برمیگردانیم:
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gorilla/mux" ) type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, } func createEvent(w http.ResponseWriter, r *http.Request) { var newEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event id, title and description only in order to update") } json.Unmarshal(reqBody, &newEvent) // Add the newly created event to the array of events events = append(events, newEvent) // Return the 201 created status code w.WriteHeader(http.StatusCreated) // Return the newly created event json.NewEncoder(w).Encode(newEvent) } func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) router.HandleFunc("/event", createEvent).Methods("POST") log.Fatal(http.ListenAndServe(":8080", router)) }
برای نمایش تمام رویدادها باید دادههای events
را نمایش دهیم:
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gorilla/mux" ) type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, } func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func createEvent(w http.ResponseWriter, r *http.Request) { var newEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event id, title and description only in order to update") } json.Unmarshal(reqBody, &newEvent) // Add the newly created event to the array of events events = append(events, newEvent) // Return the 201 created status code w.WriteHeader(http.StatusCreated) // Return the newly created event json.NewEncoder(w).Encode(newEvent) } func getAllEvents(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(events) } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) router.HandleFunc("/event", createEvent).Methods("POST") router.HandleFunc("/events", getAllEvents).Methods("GET") log.Fatal(http.ListenAndServe(":8080", router)) }
برای نمایش یک رویداد خاص باید باید مقدار ID
را بهکمک Mux دریافت کنیم و درنهایت اگر ID
ارسال شده با رویدادهای موجود در دیتابیس شبیهسازی شده همخوانی داشت، تمام دادههای آن رویداد را نمایش دهیم:
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gorilla/mux" ) type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, } func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func createEvent(w http.ResponseWriter, r *http.Request) { var newEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event id, title and description only in order to update") } json.Unmarshal(reqBody, &newEvent) // Add the newly created event to the array of events events = append(events, newEvent) // Return the 201 created status code w.WriteHeader(http.StatusCreated) // Return the newly created event json.NewEncoder(w).Encode(newEvent) } func getOneEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] // Get the details from an existing event // Use the blank identifier to avoid creating a value that will not be used for _, singleEvent := range events { if singleEvent.ID == eventID { json.NewEncoder(w).Encode(singleEvent) } } } func getAllEvents(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(events) } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) router.HandleFunc("/event", createEvent).Methods("POST") router.HandleFunc("/events", getAllEvents).Methods("GET") router.HandleFunc("/events/{id}", getOneEvent).Methods("GET") log.Fatal(http.ListenAndServe(":8080", router)) }
برای بهروزرسانی یک رویداد دقیقا شبیه بخش قبل عمل میکنیم و از Mux برای دریافت ID
استفاده خواهیم کرد. اگر رویدادی با این ID
وجود داشته باشد، بهسراغ مقادیر ارسال شده در بدنهی درخواست PATCH
میرویم و آنها را با مقادیر فعلی رویداد جایگزین میکنیم. درنهایت رویداد بهروزرسانی شده را نمایش میدهیم:
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gorilla/mux" ) type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, } func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func createEvent(w http.ResponseWriter, r *http.Request) { var newEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event id, title and description only in order to update") } json.Unmarshal(reqBody, &newEvent) // Add the newly created event to the array of events events = append(events, newEvent) // Return the 201 created status code w.WriteHeader(http.StatusCreated) // Return the newly created event json.NewEncoder(w).Encode(newEvent) } func getOneEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] // Get the details from an existing event // Use the blank identifier to avoid creating a value that will not be used for _, singleEvent := range events { if singleEvent.ID == eventID { json.NewEncoder(w).Encode(singleEvent) } } } func getAllEvents(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(events) } func updateEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] var updatedEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event title and description only in order to update") } json.Unmarshal(reqBody, &updatedEvent) for i, singleEvent := range events { if singleEvent.ID == eventID { singleEvent.Title = updatedEvent.Title singleEvent.Description = updatedEvent.Description events[i] = singleEvent json.NewEncoder(w).Encode(singleEvent) } } } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) router.HandleFunc("/event", createEvent).Methods("POST") router.HandleFunc("/events", getAllEvents).Methods("GET") router.HandleFunc("/events/{id}", getOneEvent).Methods("GET") router.HandleFunc("/events/{id}", updateEvent).Methods("PATCH") log.Fatal(http.ListenAndServe(":8080", router)) }
حذف یک رویداد با متد DELETE
انجام میشود بنابراین مقدار ID
ارسال شده در درخواستهایی با متد DELETE
را به کمک Mux دریافت خواهیم کرد و آن را با دیتابیس شبیهسازی شده مقایسه میکنیم. اگر در دیتابیس ما رویدادی با این ID
وجود داشته باشد آن را حذف خواهیم کرد و درنهایت موفقیتآمیز بودن حذف رویداد را نمایش میدهیم:
package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "github.com/gorilla/mux" ) type event struct { ID string `json:"ID"` Title string `json:"Title"` Description string `json:"Description"` } type allEvents []event var events = allEvents{ { ID: "1", Title: "Introduction to Golang", Description: "Come join us for a chance to learn how golang works and get to eventually try it out", }, } func homeLink(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Welcome home!") } func createEvent(w http.ResponseWriter, r *http.Request) { var newEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event id, title and description only in order to update") } json.Unmarshal(reqBody, &newEvent) // Add the newly created event to the array of events events = append(events, newEvent) // Return the 201 created status code w.WriteHeader(http.StatusCreated) // Return the newly created event json.NewEncoder(w).Encode(newEvent) } func getOneEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] // Get the details from an existing event // Use the blank identifier to avoid creating a value that will not be used for _, singleEvent := range events { if singleEvent.ID == eventID { json.NewEncoder(w).Encode(singleEvent) } } } func getAllEvents(w http.ResponseWriter, r *http.Request) { json.NewEncoder(w).Encode(events) } func updateEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] var updatedEvent event // Convert r.Body into a readable formart reqBody, err := ioutil.ReadAll(r.Body) if err != nil { fmt.Fprintf(w, "Kindly enter data with the event title and description only in order to update") } json.Unmarshal(reqBody, &updatedEvent) for i, singleEvent := range events { if singleEvent.ID == eventID { singleEvent.Title = updatedEvent.Title singleEvent.Description = updatedEvent.Description events[i] = singleEvent json.NewEncoder(w).Encode(singleEvent) } } } func deleteEvent(w http.ResponseWriter, r *http.Request) { // Get the ID from the url eventID := mux.Vars(r)["id"] // Get the details from an existing event // Use the blank identifier to avoid creating a value that will not be used for i, singleEvent := range events { if singleEvent.ID == eventID { events = append(events[:i], events[i+1:]...) fmt.Fprintf(w, "The event with ID %v has been deleted successfully", eventID) } } } func main() { router := mux.NewRouter().StrictSlash(true) router.HandleFunc("/", homeLink) router.HandleFunc("/event", createEvent).Methods("POST") router.HandleFunc("/events", getAllEvents).Methods("GET") router.HandleFunc("/events/{id}", getOneEvent).Methods("GET") router.HandleFunc("/events/{id}", updateEvent).Methods("PATCH") router.HandleFunc("/events/{id}", deleteEvent).Methods("DELETE") log.Fatal(http.ListenAndServe(":8080", router)) }