Веб-разработка на Go
Теория: Сериализация данных в JSON
В вебе взаимодействие происходит по схеме клиент-сервер. Клиент отправляет запрос, а сервер отдает ответ.
Обычно в запросах и ответах содержится информация о том, что именно клиент хочет от сервера. Например, при запросах на получение данных указывается, какие данные сервер должен вернуть. Чаще всего эти данные представляются в виде структур, при этом нам нужно передать их в текстовом виде. В этом случае разработчики используют сериализацию.
В этом уроке мы разберем формат сериализации данных — JSON. Мы рассмотрим, как сериализовать и десериализовать данные в JSON в Golang.
Сериализация и десериализация в Golang
Представим, что нам нужно получить список пользователей. Клиент отправляет запрос GET /users, а сервер отдает ответ в виде списка пользователей. Список пользователей — это массив структур. Каждая структура содержит информацию о пользователе. Например, имя, фамилию, возраст, пол.
Мы знаем, что HTTP — это текстовый протокол, поэтому в запросе и ответе могут быть только текстовые данные. Поэтому нам нужно передать массив пользователей в текстовом виде. В этом нам поможет сериализация — процесс преобразования данных в строку. Сервер сериализует массив пользователей в строку и передает клиенту. Клиент может десериализовать строку обратно в массив структур пользователей.
Десериализация — это процесс преобразования сериализованной строки обратно в данные, которое понимает приложение.
На схеме ниже показано, как происходит сериализация и десериализация данных при отправке HTTP-ответа от сервера к клиенту:
Сервер сериализует объекты пользователей в строку, отправляет это в теле HTTP-ответа, а клиент читает тело ответа и десериализует строку обратно в данные.
Существует множество протоколов сериализации данных. Они отличаются способами преобразования данных в строку и форматами сериализованной строки. Наиболее популярные протоколы сериализации данных: JSON, XML, YAML, MessagePack и Protocol Buffers.
В этом курсе мы разберем самый популярный протокол сериализации данных — JSON. У него есть следующие преимущества:
- Простой в изучении, чтении и понимании
- Поддерживается большинством языков программирования
- Формат достаточно компактный по сравнению с широко используемым в прошлом XML
Перед тем, как продолжить, ознакомьтесь с этим форматом сериализации в документации.
Для сериализации и десериализации данных в JSON используется стандартная библиотека. Для этого в ней есть две функции:
json.Marshal()— сериализует данные в JSONjson.Unmarshal()— десериализует данные из JSON
Так в GO происходит сериализация и десериализация структуры:
При запуске программы видим вывод:
В данном Go-приложении мы преобразовали объект пользователя User в JSON-строку и обратно. В результате мы получили ту же структуру User, но с пустым полем password, потому что указали, что это приватное поле. Если бы мы отправили такую JSON-строку по сети другому веб-приложению, то оно смогло бы восстановить изначальный объект User без поля password.
Важные моменты работы с JSON в Go:
-
В структуре сериализуются только публичные свойства, которые написаны с заглавной буквы. В нашем примере свойство
password— приватное, поэтому оно не попало в JSON-строку. Такое же правило действует и на десериализацию. Если мы добавим значениеpasswordв JSON-строку, то это значение все равно не попадет в десериализованную структуру -
В JSON-строке можно указывать название свойства, которое будет отличаться от названия свойства в структуре. Для этого используется тег
json:"". В нашем примере мы указали тег для свойстваIDв видеjson:"id". Так можно указывать, в каком виде должно называться свойство в JSON-строке в зависимости от соглашений в проекте -
При описании тега
json:""можно указать опциюomitempty. Эта опция говорит о том, что если значение свойства является нулевым, то это поле не нужно включать в сериализованную строку
Мы научились работать с JSON в Golang, теперь рассмотрим, как использовать этот формат в веб-приложениях.
JSON в веб-приложении
В веб-приложениях JSON используется, чтобы обменивать данные между клиентом и сервером. Клиент может отправлять HTTP-запрос с телом запроса в формате JSON, а сервер может возвращать HTTP-ответ с телом в формате JSON.
Веб-клиент отправляет JSON в теле запроса в случае, когда нужно изменить состояние чего-либо. Например, если пользователь заполнил форму регистрации, то веб-клиент отправит JSON с данными формы на сервер. Сервер в этом случае сохранит нового пользователя в базе данных.
Сервер возвращает ответ с JSON, когда клиент запрашивает данные. Например, клиент запросил список курсов на Хекслете, и сервер вернул JSON массив структур курсов.
Реализуем эти концепции на примере Fiber веб-приложения. В Fiber работа с JSON происходит через контекст запроса c *fiber.Ctx. Для этого есть два метода:
c.BodyParser()— преобразует JSON-тело запроса в объектc.JSON()— отправляет JSON-строку в теле ответа
Реализуем веб-приложение для сохранения логов, в котором отправим JSON в теле запроса и получим JSON в теле ответа.
В приложении будет единственный метод /logs, который будет принимать POST-запросы на сохранение записи. В теле запроса передается структура одной записи логов. В ответе веб-приложение возвращает структуру с идентификатором сохраненной записи:
Запускаем веб-приложение и отправляем запрос на сохранение тестовой записи:
В ответ получаем идентификатор:
В данном веб-приложении мы описали структуры запроса и ответа с публичными свойствами и JSON-тегами. Благодаря этому, мы смогли использовать структуру запроса CreateLogEntryRequest в методе c.BodyParser(), чтобы десериализовать тела запроса из JSON. Также мы использовали структуру ответа CreateLogEntryResponse в методе c.JSON(), чтобы сериализовать тела ответа в JSON.
Выводы
В этом уроке мы изучили, что такое сериализация — процесс преобразования структур данных в строку. И десериализация — процесс преобразования сериализованной строки обратно в данные.
Еще мы разобрали самый популярный формат сериализации данных — JSON, так как он простой в генерации и чтении по сравнению с аналогами.
Напомним еще несколько важных моментов из урока:
- В Go у структур сериализуются только публичные поля
- В фреймворке Fiber есть функция
c.BodyParser(), которая позволяет десериализовать JSON тело запроса в структуру - В фреймворке Fiber есть функция
c.JSON(), которая позволяет сериализовать структуру тела ответа в JSON
