Почти день был потрачен на проблему с запросом PUT к зародышу API. Они роняли сервак, ничего не возвращали, но самое сложное: сервер возращает корректный body (JSON), на хводе корректный JSON, а на серваке - jetty.server.HttpInput и хоть ты тресни.

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

Content-Type: application/x-www-form-urlencoded

Ок, вроде бы понятно: мы присылаем запрос, говоря что это форма, там куда инфы. Jetty умен, кэширует это дело и не показывает кому попало. Что бы его зачитать, надо прям JAVA’скими методами прочитать байты из потока, конвертануть и собрать в строку. Но блин, я же JSON шлю! Через JQuery:

    $.ajax({url:"/api/events/555",
            type:'PUT',
            data:JSON.stringify({value:23}),
            dataType:'application/json',
            success: function(data, d, xrh) { console.log(data) }});

Оказалось, что надо не dataType а contentType.

XMLHttpRequest:

var req = new XMLHttpRequest();
req.open("PUT", "/api/events/12", true);
req.send(JSON.stringify({value:123}));

Тоже были проблемы, пока перед отправкой запроса не выполнил

    req.setRequestHeader('Content-Type', 'application/json');

И все заработало.

Ладно, с этим разобрались. Mock-API есть, надо бы тесты наклепать: все-таки API, к тому же отказ от noir-validation шел на пользу. А тем ведь BDD, ммм… Тут же вспомнилась либа, которая висела в dependencies профиля dev - ring-mock. Нашел, поправил, начал смотреть что это и сразу как стало ясно. На самом деле, про mock я читал статью в сфере С++. Там mock это заглушка компонента, который должен вызываться целевым компонентом, который мы тестируем. Штучка для интеграционных тестов. Мы просто мокаем что-то жирное, а в тестах указываем, что вот этот тестируемый метод, должен 3 раза вызвать метод “мокнутого” компонента.

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

(mock/request :get "/api/events/123")

Дальше кормим этот запрос серверному обработчику и сравниваем полученный response с ожиданиями. И тут то кульминация: у ответа Content-Type: "text/html; charset=utf-8". Стерва. Ведь висит же middleware wrap-json-response. Ну думаю, сейчас я тебя…под middleware засуну!

(defn wrap-content-json [handler]
    (fn [req] (update-in (handler req) [:headers "Content-Type"]
        (fn [_] "application/json"))))

Мимолетом прогуглил как сделать просто замену: не нашел - сам запилил. Конечно все делается проще:

(defn wrap-content-json [handler]
    (fn [req] (assoc-in (handler req) [:headers "Content-Type"]
        "application/json"))

Эх… Но не пригодился он мне. Оказывается надо возвращать Clojure’ские объекты, а не строки и тогда будет сам устанавливаться Content-Type.