Как да изложите JSON крайна точка в Elixir без никаква рамка?

Болките от нов език

Много разработчици на Elixir идват от света на Ruby. Това е много зряла среда когато става въпрос за наличните библиотеки и рамки на общността. И това е, което понякога ми липсва в Elixir. Когато искам да интегрирам услуга на трета страна, резултатът може да бъде следният:

restful

  1. има официална добре поддържана библиотека (много рядко)
  2. има официална, но остаряла или бъги библиотека (случва се понякога)
  3. има добре поддържана библиотека на общността (от време на време)
  4. има библиотека в общността, но вече не се поддържа (много често)
  5. има множество библиотеки, всяка написана за нуждите на техния автор и с липсващи функции (най-популярните)
  6. има собствена библиотека, съчетаваща всичко най-добро от горното ... (твърде често)

Прост JSON API в Elixir

Може да се изненадате, но Руби не винаги е на Rails. Не е задължително да е свързано и с мрежата. Въпреки това, в този конкретен случай, нека поговорим точно за мрежата.

Когато става въпрос за излагане на една крайна точка RESTful, обикновено имаме много възможности за избор:

Това са само примерите, които съм използвал лично. Моите колеги са щастливи потребители на Sinatra и те са опитвали Hanami и преди. Мога да избирам каквото имам нужда и харесвам, дори в зависимост от текущото ми настроение.

Когато обаче преминах на Elixir, се оказа, че изборът е ограничен. Въпреки че има няколко алтернативни „рамки“ (които поради очевидните причини няма да споменавам тук), те са почти неизползваеми!

Прекарах целия ден, играейки с всяка библиотека, споменавана някога в Интернет. Опитах се да разположа прост HTTP2 сървър в Heroku действайки като бот на Slack, но в края на деня се предадох. Буквално нищо, което открих, не успя да покрие основните ми изисквания.

Phoenix не винаги е решението

P hoenix е любимата ми уеб рамка, просто не винаги се нуждая от нея. Поколебах се да го използвам, защото исках да избегна изтеглянето на цялата рамка само за една крайна точка, без значение колко лесно би било.

Не можех да използвам нито една библиотека, защото, както споменах, нито едно от това, което открих, не отговаря на моите нужди (т.е. основно маршрутизиране с обработка на JSON) и беше достатъчно удобен за лесно и бързо разполагане на Heroku. „Да вървим една крачка назад“ - помислих си.

Имайте предвид, че самият Феникс е изграден върху нещо, нали?

Plug & Cowboy за спасяването

Ако искаме да приложим наистина минимален Ruby сървър, просто ще използваме rack, който е модулен интерфейс на Ruby уеб сървър.

За щастие в Elixir можем да използваме подобно нещо. Тук ще използваме следните елементи:

  • cowboy - малък и бърз HTTP сървър за Erlang/OTP, осигуряващ пълен HTTP стек и възможности за маршрутизация, оптимизирани за ниска латентност и малко използване на паметта
  • plug-connection адаптери за различни уеб сървъри в Erlang VM и връзката е директен интерфейс към основния уеб сървър
  • отрова - просто JSON библиотека за Elixir

Искам да внедря компоненти като Endpoint, Router и JSON Parser. След това бих искал да разположа това на Heroku и да мога да обработвам входящите заявки към изложената крайна точка. Погледнах ли как може да се постигне.

Приложение

Уверете се, че вашият проект Elixir е контролиран. За да имате това, трябва да го създадете като:

Осигурете следния запис в mix.exs:

и създайте файла lib/minimal_server/application.ex:

Библиотеки

В нашия mix.exs ще трябва да изтеглите следните библиотеки:

И след това ги компилирайте:

Крайна точка

Готови сме да изградим входна точка към вашия сървър. Нека тогава създадем lib/minimal_server/endoint.ex файл:

Plug осигурява Plug.Router за изпращане на входящи заявки въз основа на пътя и метода. Когато маршрутизаторът бъде извикан, той ще извика: match match, представен от match/2 функция, отговорна за намирането на съвпадащ маршрут, и след това ще го препрати към plug: dispatch, който ще изпълни съответстващия код.

Тъй като искаме нашият API да бъде съвместим с JSON, ние прилагаме Plug.Parsers тук. Ще го използваме за синтактичен анализ на тялото на заявката, защото обработва заявките за приложения/json с даденото: json_decoder .

И накрая, създадохме временен „маршрут за хващане“, който отговаря на всички заявки и отговаря с код на състоянието HTTP not found (404).

Рутер

Рутерът е последната стъпка от нашето приложение. Това е последната част от целия конвейер, който създадохме: от заявката на уеб браузъра до изобразяването на отговора.

Ще обработим входящото обаждане от клиент и ще кодираме някакво съобщение там:

В нашия рутер по-горе, заявката ще съвпада само ако е метод GET и маршрутът е /. Рутерът ще отговори с тип на съдържанието "application/json" и тялото:

Обвързвайки ги заедно

Сега е моментът да разширим нашата Крайна точка, за да препращаме заявки към рутера и да разширим нашето Приложение, за да създадем самата Крайна точка.

Първото нещо, което можем да направим чрез добавяне

линия към модула MinimalServer.Endpoint. Това ще гарантира, че всички заявки към/бот ще бъдат препращани и обработвани от нашия рутер .

Второто нещо може да се направи чрез разширяване на endpoint.ex с функции child_spec/1 и start_link/1:

Сега можете да модифицирате application.ex, като добавите MinimalServer.Endpoint към списъка, върнат от children/0 .

За да стартирате сървъра, достатъчно е да изпълните: