Статьи

NancyFX — Пересмотр согласования контента и API (часть 1)

Я подумал, что вернусь к этой теме, так как я не верю, что в прошлый раз я достаточно справедлив, и я считаю, что это действительно важно при создании API, который будет использоваться не только публикой или клиентом, но и вами также !

Когда браузер запрашивает text/htmlсогласование с сервером. Так что на самом деле ваш веб-сайт — это API, вы Views— просто дополнительный тип контента, который ваш API обслуживает по запросу.

пример

Допустим, вы создаете Twitter; На начальной странице показан список твитов, поэтому браузер выполняет вызов, /tweetsа сервер отвечает списком твитов, отображаемых с помощью HTML.

Как только страница загружена, клиент использует JavaScript для загрузки новых твитов, поэтому он /tweetsснова вызывает , на этот раз возвращает jsonрезультат, и механизм шаблонов на стороне клиента затем отображает и добавляет их в верхнюю часть существующего списка, сохраняя клиента в курсе последних твитов.

Что приятно, новые данные не нужно записывать на сервер!

Примечание: я не собираюсь обсуждать API RESTful, это просто вызовет слишком много аргументов.

Нужен код пожалуйста

Хорошо, давайте посмотрим на это в действии по-настоящему. Когда я продемонстрировал это в своем предыдущем посте, я показал несколько сложные переговоры. На этот раз я собираюсь показать супер простой сценарий.

У нас есть ProductsModule, это может Getодин продукт, или это может Getсписок продуктов.

public class ProductsModule : NancyModule
{
    public ProductsModule(IProductRepository productRepository)
        :base("products")
    {
        Get["/{id}"] = _ =>
        {
            var product = productRepository.Get((int)_.id);

            return product;
        };

        Get["/"] = _ =>
        {
            var products = productRepository.List();

            return products;
        };
    }
}

Используя плагин Chrome «Почтальон», который можно найти в Интернет-магазине Chrome , мы можем вызывать некоторые вызовы для получения данных. Мы указываем URL, VERBи добавляем некоторые заголовки. В этом случае мы добавим один заголовок. Acceptгде мы указываем, что мы хотим application/xml.

Когда мы вызываем это, мы получаем результат XML наших продуктов:

Когда мы делаем тот же вызов, но указываем Acceptзаголовок, application/jsonмы получаем результат в формате JSON.

Хорошо, правда? Пока что мы не написали никакого кода, кроме как возвращать некоторые данные в указанную конечную точку. Давайте посмотрим на первый маршрут, это маршрут Get By Id, и все, что мы возвращаем, это один продукт.

Теперь, если мы укажем Accept как то, что запрашивает браузер, text/htmlмы ожидаем визуализированный HTML.

Бэм, мы получаем ошибку, но это только потому, что представление еще не существует. По умолчанию NancyFX ищет представление с тем же именем возвращаемого типа.

Поскольку мы вернули «продукт», имя представления, которое Нэнси будет искать, — это typeof(Product).Nameили Product. Поэтому, если мы создадим новый вид продукта для отображения некоторых данных:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>

    <div>
        Id: @Model.Id
        <br />
        Name: @Model.Name
        <br />
        Price: $@Model.Price
    </div>

</body>
</html>

Супер супер просто, теперь, когда мы снова вызываем тот же маршрут, мы получаем:

Теперь у нас есть единый API, который возвращает JSON, XML или HTML.

Непростые проблемы

Вот где дела обстоят непросто: если мы хотим вернуть коллекцию с представлением, NancyFX попытается преобразовать его List<Product>в его имя и ищет представление. В результате поиск представления по названию List`1может показаться неудачным, но, как ни странно, на самом деле вы можете создать представление с обратной цитатой.

Итак, давайте создадим новый файл и назовем List`1.sshtmlего базовым HTML:

<!DOCTYPE html> 
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>

    @Each
    <div>
        Id: @Current.Id
        <br />
        Name: @Current.Name
        <br />
        Price: $@Current.Price
    </div>
    <hr>
    @EndEach

</body>
</html>

Примечание: если вам интересно, это не Razor, это Super Simple View Engine от Нэнси 🙂

Теперь, если мы снова запустим сайт и нажмем, /productsмы получим:

резюмировать

До сих пор мы создали одну конечную точку с очень небольшим количеством кода, который может отвечать JSON / XML / HTML. Далее я собираюсь показать, как Negotiateдает вам больше гибкости.