- PVSM.RU - https://www.pvsm.ru -

Фреймворк NancyFX и сервисы в стиле REST

Здравствуйте, дамы и господа. Подумалось, в нашей пятничной рубрике еще не было ни одной дельной статьи о надувных динозаврах в контексте гостиничного бизнеса.

Если вдруг вас совсем не интересует фреймворк NancyFX и микросервисы на платформе .NET, создаваемые с его помощью — почитайте про динозавров!

Наш офис ни с чем не перепутаешь — у нас тут установлены надувные динозавры, целый парк видавших виды мониторов, а весь коллектив постоянно гоняет йоркширские чаи. Но, чтобы уделять на такой живительный размандык то время, которого он, безусловно, заслуживает, мы должны быстро и эффективно решать наши основные задачи – в частности, поддерживать сервис, при помощи которого наши клиенты могут бронировать гостиничные номера.

Чтобы это получалось еще лучше, мы постепенно переделали наш сегмент базы кода под микросервисную архитектуру [1]. Первым делом мы написали API Reservations, выделив весь функционал, связанный с созданием и извлечением записей о бронировании в отдельный домен с независимыми системами версионирования, релизов и обслуживания. Так нам удалось без труда поддерживать новые кроссплатформенные фронтенды – например, мобильную версию и форму бронирования на основе Node.js

Но затем мы пошли далее и выделили такие этапы бронирования (например, отправку сообщений с подтверждениями), которые не обязательно должны осуществляться строго до того, как подтверждение будет возвращено на фронтенд. Сам процесс бронирования можно свести к двум наборам действий: заказываем номер в отеле и сохраняем соответствующую запись, если можем быть уверены, что после этого обе операции будут выполнены максимально оперативно. Для этого мы добавили в наш инструментарий очереди сообщений и задействовали набор процессоров команд и событий, предназначенных как раз для обработки таких внеполосных задач.

Вскоре нам понадобился набор сервисов, каждый из которых отвечал за конкретную часть домена. Чтобы их разработать, нам потребовалось быстро и легко написать REST API, желательно без пробуксовки. Вот тогда мы и нашли Nancy.

NancyFx [2] – потрясающий легкий веб-фреймворк для .NET. Если вы ориентируетесь во фреймворках для других языков, например, Sinatra и Express, то уже вполне представляете, что от него ожидать. С другой стороны, если знакомы лишь с такими .NET-глыбами как Microsoft MVC и WCF, то, вполне возможно, вас ждет приятный сюрприз.

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

Шаг 1: Создаем консольное приложение на C#

Разумеется, это можно сделать и на другом языке для платформы .NET. Даже на VB.

Шаг 2: Импортируем Nancy

Nancy предоставляется в виде пакетов Nuget, так что рекомендую воспользоваться менеджером пакетов Visual Studio – самым удобным инструментом для импорта двоичных файлов в проект и ссылки на них. В данном случае нам понадобится пакет Nancy.Hosting.Self, зависящий от основного пакета Nancy.

Шаг 3: Создаем хост Nancy

В методе Main (или эквивалентной входной точке программы) напишите:

using (var host = new NancyHost(new Uri("http://localhost:1234"))
{
    Console.ReadKey();
}

Вы уже создали консольное приложение, которое слушает HTTP на порте 1234. На самом деле, нам нравится так делать, это простая реализация обратных прокси, передающих внешние HTTP-запросы управляемому процессу. Однако, Nancy поддерживает и OWIN, традиционный IIS-хостинг.

Шаг 4: Создаем маршрут к ресурсу

Создаем наш первый маршрут, наследуя класс Module из Nancy. Напишите вот это в файле с новым проектом:

class Dinosaur
{
    public string Name { get; set; }
    public int HeightInFeet { get; set; }
    public string Status { get; set; }
}

class DinosaurModule : NancyModule
{
    private static Dinosaur dinosaur = new Dinosaur()
    {
        Name = "Kierkegaard",
        HeightInFeet = 0,
        Status = "Deflated"
    };

    public DinosaurModule()
    {
        Get["/dinosaur"] = parameters => dinosaur;
    }
}

При запуске хоста Nancy просматривает вашу сборку и ищет в ней классы, наследующие NancyModule. Они будут инстанцироваться всякий раз при поступлении запроса, обеспечивать маршрутизацию и действия. В данном случае мы создаем простой маршрут GET в конструкторе модуля и пользуемся лямбда-выражением, при помощи которого возвращаем определенный нами объект модели. Если вызвать localhost [3]:1234/dinosaur без заголовка с типом содержимого, то модель динозавра придет нам в формате JSON. Запустите приложение, попробуйте.

Шаг 5: Добавляем операцию записи

До сих пор наш ресурс был только для чтения. Добавьте в конструкторе DinosaurModule такой код:

Post["/dinosaur"] = parameters =>
{
    var model = this.Bind<Dinosaur>();
    dinosaur = model;
    return model;
};

Привязка принимает тело HTTP-запроса и пробует ассоциировать его с заданным типом модели. Попытайтесь послать следующий код на localhost [3]:1234/dinosaur, тип содержимого — application/json:

{
    "name": "Kierkegaard",
    "heightInFeet": 6,
    "status": "Inflated"
}

Тело запроса следует привязать к классу Dinosaur и присвоить нашему статическому члену Dinosaur. Как и в случае с конечной точкой Get, мы возвращаем модель, после чего Nancy сериализует модель JSON. В Nancy есть такие возможности как обсуждение содержимого и рендеринг представления, но в данном демонстрационном примере нам вполне подойдет поведение, задаваемое по умолчанию.

Шаг 6: Создаем и возвращаем индексированные ресурсы

Как правило, когда мы пишем REST API, нам требуется по несколько от каждого ресурса. Давайте немного модифицируем класс:

public class DinosaurModule : NancyModule
{
    private static List<Dinosaur> dinosaurs = new List<Dinosaur>()
    {
        new Dinosaur() {
           Name = "Kierkegaard",
           HeightInFeet = 6,
           Status = "Inflated"
        }
    };

    public DinosaurModule()
    {
        Get["/dinosaurs/{id}"] = parameters => dinosaurs[parameters.id - 1];
        Post["/dinosaurs"] = parameters =>
        {
            var model = this.Bind<Dinosaur>();
            dinosaurs.Add(model);
            return dinosaurs.Count.ToString();
        };
    }
}

Теперь маршрут - /dinosaurs. Объект parameters в лямбда-выражении – это, в сущности, динамический тип, комбинирующий значения из маршрута, строки запроса и тела запроса. Определяя параметр {id} в рамках маршрута, можно захватывать его, а потом с его помощью извлекать нужный нам ресурс.

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

Шаг 7: Ваш ход

В финале нашей весьма обзорной экскурсии у нас получилась такая спартанская оконечная REST-точка. А что дальше? Естественно, мы хотим держать наши ресурсы в каком-то долговременном хранилище данных, а не в памяти, но что насчет валидации, обработки ошибок, безопасности?

При всей легкости и простоте Nancy прямо «из коробки» решает и многие подобные вопросы, а также предоставляет другие возможности, которые вы сможете с легкостью внедрить в проект.
Итак, общее представление о Nancy вы составили – а теперь почитайте документацию [4].

Автор: Издательский дом «Питер»

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/c-2/224832

Ссылки в тексте:

[1] микросервисную архитектуру: http://martinfowler.com/articles/microservices.html

[2] NancyFx: http://nancyfx.org/

[3] localhost: http://localhost

[4] документацию: https://github.com/NancyFx/Nancy/wiki/Documentation

[5] Источник: https://habrahabr.ru/post/318334/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best