REST API приложение на Go: пошаговый туториал

В этой статье мы рассмотрим, как создать REST API приложение на языке Go: лучшая пошаговая инструкция с использованием популярной архитектуры.

REST API приложение на Go: пошаговый туториал

Причина популярности Go заключается в его простоте, мощных функциях и производительности. В качестве первого контакта с этим языком предлагаем написать небольшое REST API приложение, в котором мы сможем просматривать список книг или одну книгу, удалять, обновлять и добавлять книги в список.

Итак, у нас будет пять HTTP запросов следующего вида:

/books - GET
/books/{id} - GET
/books - POST
/books/{id} - PUT
/books/{id} - DELETE

Метод GET предполагает, что мы будем просматривать или список всех книг, или информацию одной книги по её id. В POST методе мы будем добавлять новую книгу, PUT – обновлять, DELETE – удалять.

Программы на Go начинаются с определения пакета.

package main

Дальше мы импортируем нужные нам пакеты с помощью функции import:

import (
  "log"
  "net/http"
  "math/rand"
  "strconv"
  "encoding/json"
  "github.com/gorilla/mux"
)

В конце можно заметить библиотеку gorilla/mux, которая не входит в стандартный пакет библиотек, поставляемых Go. Библиотека gorilla/mux используется для определения маршрутов HTTP запросов. Для начала нам нужно скачать её на проект с помощью команды в терминале go get github.com/gorilla/mux, а потом импортировать.

Дальше мы создадим две небольшие структуры (напоминаем, что в Golang нет привычных нам классов и объектов):

type Book struct {
  ID      string `json:"id"`
  Title   string `json:"title"`
  Author *Author `json:"author"`
}

type Author struct {
  Firstname string `json:"firstname"`
  Lastname  string `json:"lastname"`
}

В структуре Book у нас содержится id книги, название и указатель на структуру Author, которая, в то же время, содержит имя и фамилию автора, написавшего книгу.

Далее мы создаём объект структуры Book:

var books []Book

Теперь, когда мы инициализировали всё, что нам понадобится для хранения данных, загрузили пакеты, можно приступать к написанию методов, обрабатывающих HTTP запросы. Первой функцией будет getBooks(), в результате работы которой мы будем видеть список всех книг. В качестве параметров передаём объект ResponseWriter и указатель на объект Request.

Также мы должны установить заголовок Content-Type, определяющий, с каким типом данных мы будет работать, а именно – json. Дальше мы формируем ответ и отправляем его пользователю.

func getBooks(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(books)
}

Функция getBook() будет показывать книгу по определённому id, который мы передаём через URL. Для начала передаём знакомые нам параметры запроса и ответа и устанавливаем заголовок. Теперь самое главное: нам нужно как-то получить id, передаваемый пользователем, с id книги, которая у нас реально существует. Для этого посмотрим на адресную строку:

127.0.0.1:8000/books/1

Чтобы достать GET-параметр 1, воспользуемся функцией библиотеки gorilla/mux Vars(), куда передаём наш запрос, а полученные данные сохраняем в переменную params. Далее с помощью цикла перебираем весь массив и сравниваем id конкретной книги с GET-параметром из адресной строки. Если они равны, формируем ответ в json и возвращаем пользователю.

func getBook(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    params := mux.Vars(r)
    for _, item := range books {
       if item.ID == params["id"] {
          json.NewEncoder(w).Encode(item)
          return
        }
    }
   json.NewEncoder(w).Encode(&Book{})
}

Функция createBook() будет отвечать за создание книги. Для этого мы инициализируем объект структуры Book, в четвёртой строке мы парсим тело запроса и связываем её с объектом book, передаваемым по ссылке. Дальше мы формируем случайный ID и включаем новую книгу в массив books с помощью встроенной функции append.

func createBook(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    var book Book
    _ = json.NewDecoder(r.Body).Decode(&book)
    book.ID = strconv.Itoa(rand.Intn(1000000))
    books = append(books, book) 
    json.NewEncoder(w).Encode(book)
}

Функции updateBook() и deleteBook() внешне очень похожи: мы также должны получить переменные запроса с помощью метода Vars(), необходимые для сравнения значений на изменение и удаление книги. Комбинируя функцию append и оператора среза мы добиваемся того, что в первом случае индексируем новый срез с уже обновлённой книгой, который включаем в массив с книгами, а во втором – удаляем срез, в котором находится книга.

func updateBook(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    params := mux.Vars(r)
    for index, item := range books {
        if item.ID == params["id"] {
            books = append(books[:index], books[index+1:]...)
            var book Book
            _ = json.NewDecoder(r.Body).Decode(&book)
            book.ID = params["id"]
            books = append(books, book) 
            json.NewEncoder(w).Encode(book)
            return
        }
    }
    json.NewEncoder(w).Encode(books)
}

func deleteBook(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    params := mux.Vars(r)
    for index, item := range books {
        if item.ID == params["id"] {
            books = append(books[:index], books[index+1:]...)
            break
        }
    }
    json.NewEncoder(w).Encode(books)
}

И, наконец, мы должны объявить функцию main – точку входа в наше приложение. Для начала создадим объект NewRouter() пакета gorilla/mux и добавим две книги в массив. Теперь осталось прописать пять маршрутов нашего приложения, определить HTTP методы и заставить приложение слушать порт 8000.

func main() {
    r := mux.NewRouter()
    books = append(books, Book{ID: "1", Title: "Война и Мир", Author: &Author{Firstname: "Лев", Lastname: "Толстой"}})
    books = append(books, Book{ID: "2", Title: "Преступление и наказание", Author: &Author{Firstname: "Фёдор", Lastname: "Достоевский"}})
    r.HandleFunc("/books", getBooks).Methods("GET")
    r.HandleFunc("/books/{id}", getBook).Methods("GET")
    r.HandleFunc("/books", createBook).Methods("POST")
    r.HandleFunc("/books/{id}", updateBook).Methods("PUT")
    r.HandleFunc("/books/{id}", deleteBook).Methods("DELETE")
    log.Fatal(http.ListenAndServe(":8000", r))
}
Чтобы убедиться, что REST API приложение работает, пропишем в терминале команду go run main.go.

Если введём в адресной строке 127.0.0.1:8000/books, то увидим следующее:

REST API на Go
Все книги

На запрос 127.0.0.1:8000/books/1 мы должны получить данные о первой книге:

REST API на Go
Одна книга

Чтобы проверить, что запросы PUT, DELETE и POST работают, воспользуемся Postman. Пишем json, который хотим отправить на добавление:

REST API на Go

Смотрим, что получилось:

Видим, что функция сработала и в нашем списке появилась новая книга. Теперь попробуем обновить одну из книг. Для этого в Postman выставляем метод PUT, в строке запроса пишем http://127.0.0.1:8000/books/1, где 1 – id обновляемой книги.

REST API на Go

Отправляем запрос и идём в браузер за результатами:

Как видно, всё работает. Осталось проверить последний метод – DELETE. Для этого в Postman выставляем DELETE, а всё остальное оставляем от метода PUT, включая id удаляемой книги.

Таким образом, мы научились писать на Go простое REST API приложение, посмотрели на язык в боевых условиях и убедились, что Go не только прост в освоении, но и быстрее многих других за счёт компилируемости и прочих особенностей.

Книги по Go и другие материалы:

МЕРОПРИЯТИЯ

Комментарии

ВАКАНСИИ

Добавить вакансию
PHP Developer
от 200000 RUB до 270000 RUB
Golang разработчик (middle)
от 230000 RUB до 300000 RUB

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ