Изучаем Go – Используем REST API в паре с шаблонами проектирования
Мы уже знаем, как отправить электронное письмо через API MailGun. В этот раз мы улучшим код, который написали пару недель назад, чтобы привлечь пользователей с сайта jsonplaceholder. Потом мы проверим новый код на работоспособность и, если вы читали предыдущий пост, вам не составит труда догадаться, что мы будем делать ...
В основном будем придерживаться того же подхода, что и ранее. Итак, от удаленного сервера мы получаем известный нами формат объекта JSON, поэтому начнем мы с создания структуры, а вернее структур. Ниже вы можете увидеть, как мы разобьем его на более мелкие части. В нем конечно есть все, что нам нужно, но я думаю, что это немного громоздкий вариант. Чтобы вам стало понятнее, объясняю: на самом деле нам не нужно заполнять всю структуру входящим JSON, мы могли бы просто получить ID, имя, имя пользователя и адрес электронной почты, и больше ни о чем не заботится. В листинге есть все варианты использования, хотя на GitHub, наверное, будут не все.
type Users []struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` Email string `json:"email"` Address struct { Street string `json:"street"` Suite string `json:"suite"` City string `json:"city"` Zipcode string `json:"zipcode"` Geo struct { Lat string `json:"lat"` Lng string `json:"lng"` } `json:"geo"` } `json:"address"` Phone string `json:"phone"` Website string `json:"website"` Company struct { Name string `json:"name"` CatchPhrase string `json:"catchPhrase"` Bs string `json:"bs"` } `json:"company"` }
Пройдемся по коду сверху вниз, и сначала получим адрес Address
type Address struct { Street string `json:"street"` Suite string `json:"suite"` City string `json:"city"` Zipcode string `json:"zipcode"` Geo struct { Lat string `json:"lat"` Lng string `json:"lng"` } `json:"geo"` }
Я уже было хотел вытащить Geo, но, в конце концов, решил, что Geo лучше оставаться в части структуры адреса. А теперь переместим Company.
type Company struct { Name string `json:"name"` CatchPhrase string `json:"catchPhrase"` Bs string `json:"bs"` }
И закончим созданием блокировки пользователей с использованием вновь созданных структур Address и Company.
type Users []struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` Email string `json:"email"` Address Address `json:"address"` Phone string `json:"phone"` Website string `json:"website"` Company Company `json:"company"` }
Здорово, что в новой итерации того же базового кода, с которого мы начали, нам нужно внести всего лишь небольшие изменения. Переименуем нашу переменную r и назовем ее переменной u, которая будет содержать наших пользователей Users.
var u Users json.Unmarshal(body, &u)
Хорошо, раз уж теперь у нас в памяти есть пользователи, что же мы можем с ними сделать? Давайте представим, что они были в списке адресатов и хотели получать обновления каждый раз, когда появлялось новое сообщение. А мы уже знаем, что отправка электронной почты через MailGun очень проста - фактически, у нас есть пакет, который мы можем просто импортировать. Как раз почти так, как я и хотел! Но прежде, разберем другое...
Используем шаблоны
Давайте кратко рассмотрим шаблоны Go. Если вы занимались веб-разработкой, то, наверное,
знакомы с Handlebars и подобными системами шаблонов - ведь все они примерно похожи друг на друга. Мы можем взять struct и использовать этот компонент для замены текста внутри уже «размеченного» фрагмента. Здесь я привел основной пример, который можно встретить в Golang Playground. Давайте разберемся, что же тут происходит.
package main import ( "os" "text/template" ) type Data struct { Name string City string } func main() { o := Data{"Steve", "Portland"} msgText := "It's {{.Name}} from {{.City}}!" t := template.Must(template.New("msg").Parse(msgText)) err := t.Execute(os.Stdout, o) if err != nil { panic(err) } }
Текст шаблона в этом примере будет выглядеть так: It's {{.Name}} from {{.City}}!. Затем мы оборачиваем template.New().Parse() с template.Must(). .Must() будет выкидывать варнинги, если .New() или .Parse() завершится неудачей. t.Execute () в данном случае заменяет токены {{}} и записывает результат непосредственно для последующего вывода пользователю. Вы по-прежнему можете поиграться с этим на игровой площадке Golang. Итак, спойлер: в выводе вы увидите такой текст: It's Steve from Portland!
Используйте пользователей Users и шаблоны, и вы сможете очень быстро производить замены и получать приятную персонализированную электронную почту.
Поработаем со списком
Вернемся к нашему исходному коду и добавим первую часть шаблонного кода прямо после теперь уже обновленной переменной Users и вызовом Unmarshal().
msgText := "To: {{.Email}}\nHi {{.Username}}! There is a new post!\n\n\n" t := template.Must(template.New("msg").Parse(msgText))
Можете увидеть, что мы используем настройку схожую с примером из шаблона. Мы заменяем электронную почту и имя пользователя тем, что содержится в переданном объекте. Но как мы можем использовать это с нашими пользователями? В этом случае мы используем for / range для того, чтобы пробежаться по данным в цикле.
for _, v := range u { err := t.Execute(os.Stdout, v) if err != nil { panic(err) } }
v будет каждый раз в цикле for хранить значение одного из наших пользователей. В этом случае нам не нужен индекс, поэтому мы используем _, чтобы указать Go, что нам не нужна эта переменная. Как и в предыдущем примере, мы вызываем t.Execute () и даем ему возможность выводить напрямую в standard out. Ну что-ж, давайте уже посмотрим как это все выглядит в коде.
Полный листинг данного поста
package main import ( "encoding/json" "io/ioutil" "net/http" "os" "text/template" ) type Address struct { Street string `json:"street"` Suite string `json:"suite"` City string `json:"city"` Zipcode string `json:"zipcode"` Geo struct { Lat string `json:"lat"` Lng string `json:"lng"` } `json:"geo"` } type Company struct { Name string `json:"name"` CatchPhrase string `json:"catchPhrase"` Bs string `json:"bs"` } type Users []struct { ID int `json:"id"` Name string `json:"name"` Username string `json:"username"` Email string `json:"email"` Address Address `json:"address"` Phone string `json:"phone"` Website string `json:"website"` Company Company `json:"company"` } func main() { APIURL := "https://jsonplaceholder.typicode.com/users" req, err := http.NewRequest(http.MethodGet, APIURL, nil) if err != nil { panic(err) } client := http.DefaultClient resp, err := client.Do(req) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var u Users json.Unmarshal(body, &u) msgText := "To: {{.Email}}\nHi {{.Username}}! There is a new post!\n\n\n" t := template.Must(template.New("msg").Parse(msgText)) for _, v := range u { err := t.Execute(os.Stdout, v) if err != nil { panic(err) } } }
Тем временем мы разобрались, как мы вкладывать структуры в программе и использовать базовые шаблоны. Все таки этот пост получился довольно длинным… В следующий раз, я немного изменю его структуру и добавлю реальную отправку почты. А после я пока еще не уверен, что же я вам расскажу!
Другие статьи из цикла:
- Изучаем Go - создание загрузчика (часть 1)
- Изучаем Go - создание загрузчика (часть 2)
- Изучаем Go - создание загрузчика (часть 3)
- Изучаем Go - создание загрузчика (часть 4)
- Изучаем Go - создание загрузчика (часть 5)
- Изучаем Go - Использование REST API
- Изучаем Go - Продолжаем работать с REST API
- Изучаем Go - Отправка REST-запросов
- Изучаем Go - Используем REST API в паре с шаблонами проектирования
- Изучаем Go - Повторная отправка электронной почты через API
Изучаем Go - Давайте станем модульными!скороИзучаем Go - Давайте станем модульными снова!скороИзучаем Go - Сборка DevLog Часть 01скороИзучаем Go - Сборка DevLog Часть 02скоро