تغییرات اخیر

در اینجا اطلاعیه‌ها، نسخه‌ها و تغییرات جدید لیارا فهرست می‌شوند.

    آموزش ساخت RESTful API با Go


    ۱۸ اردیبهشت ۱۴۰۰
    آموزش ساخت restful api با go

    در این مقاله‌ی آموزشی می‌خواهیم با زبان برنامه‌نویسی Go یک RESTful API توسعه دهیم که به کمک آن می‌توانید رویدادها را مدیریت کنید.

    پیش‌نیازها

    • فرض ما بر این است که شما از قبل با زبان Go آشنا شده‌اید و در حال حاضر این زبان برنامه‌نویسی بر روی سیستم شما نصب است.
    • پس از نصب زبان Go باید در GOPATH که اکثر افراد تمام پروژه‌هایشان را در این مسیر نگهداری می‌کنند، پروژه‌ی فعلی را توسعه دهیم بنابراین در پوشه‌ی src می‌توانید یک فولدر خاص برای این پروژه ایجاد کنید یا برای ساماندهی بیشتر پروژه‌های مختلف یک پوشه با نام github.com ایجاد کنید و در آن پوشه‌ی دیگری ایجاد کنید و نام آن را همان نام کاربری خود در GitHub قرار دهید. در نهایت در مسیر GOPATH/src/github.com/<Github username> یک پوشه‌ی جدید برای پروژه‌ی فعلی با نام دلخواه ایجاد کنید.

    مقاله‌ی مرتبط: توسعه و اجرای اولین برنامه با زبان Go

    توسعه‌ی API

    برای پیاده‌سازی ساختار اولیه‌ی پروژه می‌توانید به شکل زیر عمل کنید:

    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!

    راه‌اندازی سرور HTTP با استفاده از Gorilla Mux

    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 به شکل زیر است.

    راه‌اندازی سرور با استفاده از 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",
    	},
    }

    در این ساختار فقط از 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))
    }
    
    حذف یک رویداد

    منبع: https://medium.com/the-andela-way/build-a-restful-json-api-with-golang-85a83420c9da

    همچنین بخوانید: معرفی هاست رایگان Golang

    برچسب‌ها:

    خدمات رایگان لیارا

    ۲.۵ گیگابایت فضای ذخیره‌سازی ابری رایگان

    ۲.۵ گیگابایت Object Storage سازگار با پروتکل S3 با دیسک‌های SSD به‌صورت رایگان دریافت کنید.

    هاست رایگان برای دیتابیس‌

    دیتابیس‌های MariaDB، PostgreSQL و Redis را فقط با یک کلیک و به‌صورت رایگان تهیه کنید.

    سرویس DNS رایگان

    به سادگی دامنه‌تان را اضافه کنید و به صورت رایگان رکورد‌های آن را مدیریت کنید.

    ۱۰۰ هزار تومان اعتبار اولیه

    بعد از ثبت نام در لیارا مبلغ ۱۰۰ هزار تومان اعتبار هدیه دریافت می‌کنید که با توجه به ساعتی بودن هزینه سرویس‌ها، می‌توانید تمامی خدمات پولی را برای چندین هفته رایگان استفاده کنید.

    ارسال ۱۰۰ ایمیل تراکنشی رایگان در هر ماه

    در سرویس ایمیل لیارا شما می‌توانید تا ۱۰۰ ایمیل رایگان در هر ماه ارسال کنید و فقط برای بیش از آن هزینه پرداخت کنید. (به‌همراه دسترسی SMTP)

    هاست رایگان برای انواع وبسایت

    تفاوتی ندارد برای وبسایت خود از Node استفاده می‌کنید یا Laravel و Django، در لیارا می‌توانید به صورت کاملا رایگان آن را میزبانی کنید.

    توسعه‌دهندگان درباره‌ی ما چه می‌گویند

    تجربه کار باliara_cloud@امروز خیلی خوب بود. یکی از سرویس هام رو منتقل کردم روش و راضیم. انقد سریع و جذاب کارم راه افتادم اصن باورم نمیشد! برعکس سرویس های PaaS دیگه با اون همه پیچیدگیشون. دمتون گرم
    ...

    MohammadReza
    liara testimonial
    keikaavousi

    بعد از بسته شدن @fandoghpaas و ناراحتی همه‌مون از اینکه یه سرویس خوب و صادق نمی‌تونه از پس هزینه‌ها بر بیاد، سرویسم رو منتقل کردم به پاس لیارا (https://liara.ir @liara_cloud) . تجربه راحت و خوب. تفاوت‌هایی داشت که کمی کار می‌خواست ولی تا الان کاملا راضی.

    jadi
    liara testimonial
    jadi

    یه خسته نباشید باید به تصمیمliara_cloud@بگم،
    بعد از چندین روز سرکله زدن با سرویس های مشابه بالاخره تصمیم گرفتم لیارا رو امتحان کنم و باور نمیشه ۱۰ دقیقه بیشتر وقت نبرد،
    دمتون گرم.

    Arch
    liara testimonial
    EbadiDev

    واسه سرویس PaaS با اختلاف لیارا بهترین رابط کاربری داره و یکی از مزیت‌های سرویس دیتابیس‌شون اینه که خودشون به صورت دوره‌ای بکآپ میگیرن.
    ...

    Ali Najafi
    liara testimonial
    me_ali_najafi

    یکی از کارهای خوبی که جدیداً میکنم اینه که یه دیتابیس روی لیارا میسازم و به پروژه وصل میکنم اینطوری هم خونه و هم محل کار دیتابیس بروز رو دارم و راحت میتونم ادامه بدم کار روliara_cloud@

    Navid
    liara testimonial
    1navid

    عاشقliara_cloud@شدم درسته در حد AWS نیست ولی خب تجربه خوبی واسه پروژه های داخل ایران ارائه میده، میتونم رو CD هم اجراش کنم

    Amir H Shekari
    liara testimonial
    vanenshi

    همراه شما هستیم

    در خصوص سفارش یا استفاده از سرویس‌ها سوالی دارید؟
    تلفن واحد فروش:
    ۰۲۵-۳۳۵۵۷۶۱۹ (روزهای کاری ۹ الی ۱۷)
    تلفن واحد فروش: ۳۳۵۵۷۶۱۹-۰۲۵ (روزهای کاری ۹ الی ۱۷)