В открывающем уроке по разработке backend части на языке Go, коснемся формата представления данных JSON. Напишем код для извлечения данных о погоде, полученных из открытого источника open-meteo.com.
Эта статья открывает цикл обучающих уроков по написанию микросервисов на Go.
Прежде чем написать свой первый микросервис, нужно познакомиться с некоторыми важными концепциями, которые применяются в backend разработке. Начнем с формата передачи данных, а именно JSON. Он завоевал большую популярность и часто применяется в разработке backend систем.
Формат данных
Большие компании используют микросервисную архитектуру. Большие системы разбиваются на мелкие независимые части. Сервисы могут обмениваться данными между собой и предоставлять открытые источники (точки доступа) для получения данных. Например, банковские системы могут состоять из большого числа различных сервисов, каждый со своим назначением. Каждый сервис должен иметь надежный и понятный контракт обмена информацией. Контракт подразумевает под собой способы и формат кодирования информации от клиента к серверу. Формат должен обладать рядом характеристик, такими как:
- Область и широта применения — без поддержки форматы быстро теряют популярность
- Размер данных после преобразования — сколько будет занимать объект закодированный в данном формате
- Понятность — должен быть хорошо структурирован и читаем
- Документированность — обладает хорошей и понятной документацией
- Поддержка различных языков программирования
Процесс преобразования данных в другой формат называют также кодированием (encoding) информации.
История
Давным-давно, еще до появления языка Go был разработан скриптовый язык программирования JavaScript. На текущий момент JavaScript является основным языком, использующимся при написании веб-страниц и сайтов. Много frontend задач решается преимущественно с его помощью.
При программировании на нем, часто применяют объекты для структурирования данных. Они многим похожи на структуры в языке Go.
Пример объекта на JavaScript:
Здесь мы объявляем новый объект person с двумя свойствами (полями):
- name в виде строки
- age в виде числа
Так как JavaScript является языком с динамической типизацией, нам не нужно объявлять описание этого объекта в виде структуры.
Можно увидеть разницу между структурами в Go и объектом в JavaScript:
- Названия полей задаются через двойные кавычки
- Перед фигурными скобками нет никаких имен
Такой формат представления структурированных данных понятен и с ним удобно работать.
До определенного момента основным игроком на рынке форматов передачи данных в интернете был XML. Но XML сложнее для чтения и понимания. Поэтому его быстро заместил JSON. При этом, XML все еще используется для организации передачи данных между клиентами или серверами.
JSON
JavaScript Object Notation
Формат представления данных в текстовом виде. Основным его достоинством является его понятность и выразительность.
Данный формат жестко не привязан к языку программирования JavaScript, хотя в его названии и присутствует название этого языка. Формат стандартизирован и подчинен строгим сводам правил и соглашений.
Документация более чем исчерпывающая.
Если выразить суть формата кратко, то основной структурной единицей в нем является JavaScript объект.
Объект может состоять из нескольких вложенных элементов, таких как:
- число
- строка
- булев тип
- список
- вложенный объект
Go имеет отличную поддержку данного формата. Все типы, которые поддерживает формат JSON есть и в Go.
В стандартную библиотеку пакетов языка Go входит пакет encoding/json.
Он предоставляет две важные функции для работы с json.
Marshal
Функция позволяет закодировать (encode) структуру или карту в формат JSON.
Напишем небольшой пример, в котором превратим структуру на языке Go в строковое представление в формате JSON. Такая процедура иногда называется сериализацией или маршалингом.
На строке 4 импортируем пакет для работы с форматом JSON encoding/json.
Далее определяем структуру Person с двумя полями Name и Age. В функции main создаем объект типа Person.
На строке 19 воспользуемся функцией Marshal, которая превращает структуру в срез байт.
Все что передается по локальной или глобальной сети должно быть закодировано в поток байтов.
Обратите внимание, что необходимо использовать указатель на структуру при вызове функции Marshal.
В конце программы мы выводим строковое представление на экран, так как массив байтов и строк можно преобразовывать друг в друга.
Unmarshal
Функция Unmarshal выполняет обратное преобразование (декодирование) среза байтов в структуру. Такая процедура иногда называется десериализацией или демаршалингом.
Для того чтобы произвести обратное преобразование, создадим переменную p типа Person, которая имеет значение по умолчанию.
Далее воспользуемся функцией Unmarshal, чтобы заполнить структуру Person данными, представленными в формате JSON. Они хранятся в переменной personJson как срез байтов. Напомню, что строки можно преобразовывать в срез байтов и обратно.
Итак, мы научились превращать структуры на языке Go в представление JSON, а также узнали как это делать в обратном виде.
Давайте напишем небольшую программу, которая читает прогноз погоды, используя формат JSON.
Прогноз погоды
Сайт open-meteo.com предоставляет бесплатный ресурс для получения погоды в различных точках земного шара.
Есть хорошая документация на английском языке. На сайте можно сконфигурировать запрос на получение погоды с помощью множества различных параметров.
Для нашей задачи ограничимся погодой в Москве.
Текущую погоду можно получить с помощью отправки запроса по адресу:
Можете скопировать получившийся ответ в текстовый редактор кода и сохранить его в переменную или константу.
Данные по погоде возвращаются в виде объекта JSON.
В этом объекте наше внимание будет приковано к 21 строке и объекту current.
По ключу с названием temperature_2m содержится температура на конкретный момент времени.
Давайте напишем структуру Response для считывания (десериализации) этих данных. Также как в примере для функции Unmarshal, используем ее для заполнения структуры Response.
Возможно вы обратили внимание на запись:
`json:"latitude"`
Это так называемый тег. Он позволяет трансформировать процесс считывания атрибутов объекта.
В нашем примере атрибут latitude из объекта JSON будет записан в атрибут структуры Latitude.
В следующей части мы напишем небольшое приложение, которое посылает запрос на нужный нам адрес и получает текущую температуру в любом городе.