Сайт на Golang. Часть 1. Поднимаем сервер, пишем первые маршруты и возвращаем данные в JSON

Этой статьей я хочу запустить небольшой цикл пошаговых инструкций, в которых мы рассмотрим основные моменты, необходимые для создания и запуска полноценного сайта на Golang. Не знаю как вам, но мне бы в свое время такие статьи очень упростили процесс обучения. Сам я с трудом собирал эту информацию по крупинкам из книг на английском, статей разных авторов или ответов на всеми любимом stackoferflow.

В этой статье мы создадим и запустим свой сервер, пропишем первые маршруты роутинга и узнаем как возвращать клиенту (часть сайта, с которой работают пользователи) простой текст и данные в формате JSON.

Мы могли бы написать все в одном файле “main.go”, но я предлагаю сразу начать создавать структуру нашего проекта. Скажем, она может выглядеть следующим образом:

  • Папка “app” – здесь будет храниться исходный код нашего приложения на Golang. Внутри создадим еще две папки: “controller” – для хендлеров, обслуживающих маршруты; “model” – для описания структур и их методов.
  • Папка “public” – здесь будут находиться все внешние файлы: html, js, css, изображения и т.д;
  • файл “main.go” – основной файл нашего проекта.

В файле main.go размещаем следующий код:

package main

import (
	"github.com/julienschmidt/httprouter"
	"goSiteProject/app/controller"
	"log"
	"net/http"
)

func main() {
	//создаем и запускаем в работу роутер для обслуживания запросов
	r := httprouter.New()
	routes(r)
	//прикрепляемся к хосту и свободному порту для приема и обслуживания входящих запросов
	//вторым параметром передается роутер, который будет работать с запросами
	err := http.ListenAndServe("localhost:4444", r)
	if err != nil {
		log.Fatal(err)
	}
}

func routes(r *httprouter.Router) {
	//путь к папке со внешними файлами: html, js, css, изображения и т.д.
	r.ServeFiles("/public/*filepath", http.Dir("public"))
	//что следует выполнять при входящих запросах указанного типа и по указанному адресу
	r.GET("/", controller.StartPage)
	r.GET("/users", controller.GetUsers)
}

Я предпочитаю использовать роутер от Julien Schmidt. Он очень легковесный, функциональный и простой.

Для обслуживания запросов по первым двум маршрутам (“/” и “/users”) нам необходимо в папке (или пакете) “controller” создать функции – хендлеры, реализующие соответствующий интерфейс.

Чтобы на стартовой странице выводилось простое текстовое приветствие, создадим файл “pages.go” в нем разместим следующий код:

package controller

import (
	"fmt"
	"github.com/julienschmidt/httprouter"
	"net/http"
)

func StartPage(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	text := "Приветствую тебя на стартовой странице этого сайта!"
	//возвращаем простой текст
	fmt.Fprint(rw, text)
}

Функция “StartPage” реализует интерфейс хендлера, который обрабатывает запрос, приходящий по маршруту “/” для запросов типа GET. В нашем случае мы пока просто выводим текстовое сообщение в окно браузера при заходе на данную страницу “localhost:4444” или, чтобы было понятнее, “localhost:4444/”.

Прежде чем писать хендлер для маршрута “/users” нам потребуется создать структуру для типа данных “User” и написать функцию, которая будет возвращать нам массив с данными всех пользователей. В пакете “model” создаем файл “user.go” и размещаем там следующий код:

package model

type User struct {
	Id       int
	Name     string
	Surname  string
}

func GetAllUsers () (users []User, err error) {
	users = []User{
		{1,"Джон","До"},
		{2,"Говард","Рорк"},
		{3,"Джек","Доусон"},
		{4,"Лизель","Мемингер"},
		{5,"Джейн","Эйр"},
		{6,"Мартин","Иден"},
		{7,"Джон","Голт"},
		{8,"Сэмвелл","Тарли"},
		{9,"Гермиона","Грейнджер"},
	}
	return
}

Разбирать вопрос подключения к СУБД мы будем в следующих частях данной статьи, поэтому пока мы заполнили массив возвращаемых данных (список пользователей) вручную. Ошибок на текущий момент здесь не может быть, поэтому пока просто объявляем переменную “err” в списке возвращаемых значений и возвращаем ее в значении по умолчанию (nil) вместе с массивом пользователей “users”

Теперь создадим файл “users.go” и в нем разместим хендлер для маршрута “/users” :

package controller

import (
	"encoding/json"
	"github.com/julienschmidt/httprouter"
	"goSiteProject/app/model"
	"net/http"
)

func GetUsers(rw http.ResponseWriter, r *http.Request, p httprouter.Params) {
	//получаем список всех пользователей
	users, err := model.GetAllUsers()
	if err != nil {
		http.Error(rw, err.Error(), 400)
		return
	}
	//возвращаем список клиенту в формате JSON
	err = json.NewEncoder(rw).Encode(users)
	if err != nil {
		http.Error(rw, err.Error(), 400)
		return
	}
}

Получив массив с данными, мы преобразуем их в JSON одной простой функцией и возвращаем клиенту. В случае возникновения ошибки, мы возвращаем ее текст со статусом ответа “400” – “Bad Request”.

Запускаем сервер командой в консоли “go run main.go”.

Проверяем маршрут “/”:

И маршрут “/users”:

Как видим, все работает так, как мы запланировали. В следующей части мы рассмотрим как выводить статические и генерировать динамические HTML страницы.

4 Comments

  1. Спасибо большое! Всё доступно и понятно! Продолжаю чтение и изучение)

  2. Спасибо огромное, для начинающих отличная инфа!! У меня есть сервер хамрр и скрипты php, хочу это дело перевести на го. Задача такая- выборка из бд на основе запросов клиентского приложения, сложный поиск по многим параметрам с расчетами и вычислениями, но базу хочу одну, не обязательно реляционную, главное скорость. Можете что нибудь посоветовать?

    1. Алекс, спасибо за отзыв!
      Golang отлично работает со всеми известными популярными СУБД. Я сам, к сожалению, работал только с реляционными, поэтому могу подсказать что-то только по ним. Да и то, в своих задачах разницы в скорости между MySQL и PostgreSQL не заметил. MySQL проще на мой взгляд, PostgreSQL чаще всего используют в связке с go.

Leave a Comment

Your email address will not be published. Required fields are marked *