Пару месяцев назад мне попался пост про серверные фреймворки для Swift - сравнение производительности 4-х фреймворков на Swift для сервера между собой и с Node.js. Производительность меня заинтересовала. Судя по результатам, лучшим оказался Perfect. Через месяц автор выложил ещё одно сравнение производительности, но тестировал уже не в macOS, а в Linux. И снова Perfect оказался в лидерах.
На этих выходных я решил как следует его потрогать. Перед этим я бегло посмотрел в 4 сравниваемых фреймворка: Perfect, Kitura, Vapor и Zewo. Требований у меня к фреймворку было не много, кроме стандартного роутинга запросов и выдачи ответов, мне нужно:
- Поддержка шаблонизаторов, чтобы отдавать не только JSON, но и HTML.
- Поддержка сетевых запросов, т.к. в самом Foundation ничего для сетевых запросов ещё не готово.
- Желательно, чтобы были готовые библиотеки для работы с разными БД.
Естественно, всё это нужно под Linux.
Kitura
Kitura один из самых прокачанных фреймворков. Есть библиотеки для MySQL, CouchDB, MongoDB и других. Вот только результаты тестов производительности неутешительные - он плетётся в хвосте. Правда, делают его могучие IBM, которые не только его пилят, но и активно контрибьютят в сам Swift. Вроде бы есть библиотека для сетевых запросов. Есть поддержка шаблонов, но с ними всё плохо. Есть Mustache, который работает только в macOS и его всего 3 дня назад перевели на Swift 3. Есть ещё Stencil, но с ним, когда смотрел, тоже был какой-то гемор, связанный с тем, что на последних Swift и Xcode его ещё нельзя использовать.
На GitHub дофига репозиториев с разными либами и компонентами для Kitura, при этом почти напрочь отсутствует документация. Да, есть примеры, но они все примитивные, как только ты понимаешь, что хочешь сделать что-то посложнее - тупик. Может оно всё это и умеет, но копаться в исходниках кучи библиотек, друг от друга зависящих, кажется какой-то неоправданной тратой времени.
Сегодня я решил сделать тестовый проект на нём, увидев, что у них есть библиотека для работы с CouchDB, захотел посмотреть работает ли она (потому что написанная мною за вечер не работает, об этом ниже), так swift build даже не смог разрезолвить зависимости после добавления туда зависимости Kitura-CouchDB, у которой есть в зависимостях какой-то логгер, у которого в зависимостях ещё какой-то логгер. Всё от IBM. Это какой-то ад, когда это от одного производителя и оно не работает вместе. Создал им Issue на GitHub, на этом попытка что-то закодить на нём закончилась. Пока отложил.
Начали они всего лишь в феврале этого года, надеюсь, допилят всё как следует, к тому же у IBM есть все ресурсы для этого. Буквально сегодня смотрел видео с конференции по Swift, где они продвигают бэкенд на Swift и свой фреймворк.
Update: Чтобы проект сбилдился надо было указать у зависимости версию 1.1 в Package.swift, как ответили мне на мой issue на GitHub. Может что теперь и получится. Хотя осадочек остался.
Zewo
Открываешь страницу на GitHub - показывается опять очередной примитивный роутинг запросов. Если покопаться в списке репозиториев, то видишь, что вроде бы есть и клиент для PostgreSQL, и HTTP-клиент для сетевых запросов, и ещё какая-то куча обёрток вокруг сишных либ.
Опять же, документации нет, популярность его сильно ниже, судя по количеству звёзд на GitHub. Заходя на сайт проекта хочется видеть документацию, а не 1-страничный Hello World.
Для шаблонов есть Mustache, но до сих пор не переведён на Swift 3. Непонятно, насколько активно он развивается, вроде бы компонентов много, но если они не поспевают за выходом новых версий Xcode и Swift, которые обновились уже полтора месяца назад, как-то не вызывает он доверия. Совсем. Даже попробовать не получится из-за отставаний.
Vapor
Выглядит презентабельно. Есть библиотеки для работы с MySQL, PostgreSQL, MongoDB, свой ORM. Есть HTTP-клиент для запросов. Есть шаблонизатор Leaf.
Шикарно выглядит документация. Есть текстовые и видео уроки на отдельном сайте.
Попробовать не успел, но очень хочу, несмотря на то, что у него не лучшие результаты в тесте производительности.
Update: пост про Vapor.
Perfect
Самый популярный (пока) фреймворк на Swift. По крайней мере, судя по количеству звёзд на GitHub. В тесте производительности оказался лидером. Поэтому сразу захотелось посмотреть именно на него.
На сайте классная документация по всему, что есть. Т.к. она собрана в одном месте на сайте (и дублируется на GitHub), сразу увидел что есть и обёртка над cURL для сетевых запросов, и библиотеки для баз данных - SQLite, MySQL, PostgreSQL, MongoDB и свой ORM. У этого фреймворка я у первого увидел всё, что мне было нужно (потому что у некоторых других просто нет нормальной документации) и именно его и решил попробовать.
Как я пытался написать бэкенд на Perfect
С банальным роутингом Perfect справляется отлично. Синтаксис простой. Я сразу решил попробовать запилить API на нём. Для API я хотел использовать CouchDB. Поскольку готовой библиотеки у них нет, я решил быстренько набросать свою, ибо работать с CouchDB можно простыми HTTP-запросами, а в комплекте есть обёртка над сишным cURL.
За пару-тройку часов я набросал метод получения данных через GET-запрос. Тестировал всё на macOS, ура, всё работало. Сделал нужные мне методы и решил, попробую ка я ещё кое-что записывать в базу.
Вот тут то начался гемор. На macOS данные никак не хотят писаться в базу. То есть я отправляю просто POST-запрос:
let curlObject = CURL(url: url)
curlObject.setOption(CURLOPT_HTTPHEADER, s: "Content-Type: application/json; charset=utf-8")
curlObject.setOption(CURLOPT_POST, int: 1)
curlObject.setOption(CURLOPT_POSTFIELDS, s: jsonString)
curlObject.perform { code, header, body in
// code
}
CouchDB постоянно возвращал ошибку, что приходит невалидный UTF-8 JSON. Я вставлял строку, которую отправляю в базу, в отдельное приложение для тестирования REST и там данные отлично принимались. Что самое странное, если сделать много запросов из моего кода, то 1-2 запроса с одними и теми же данными база принимала и записывала, на остальные приходила ошибка. Так и не понял в чём беда. То ли это чей-то глюк, то ли я не умею использовать CURL.
Долго провозился с этой проблемой, в итоге решил просто забить и загрузить то, что уже сделал, на свой Ubuntu Server. Тут начались новые приключения.
То, что прекрасно билдится командой swift build в консоли в macOS, может не билдиться в Ubuntu. Более того, то, что билдится в Xcode, может не билдиться в консоли в macOS.
Потратив много времени на проблемные места, в основном связанные с доставанием данных из Dictionary с несколькими уровнями вложенности, сделал всё-таки, чтобы в Ubuntu код собирался.
Собрал, сделал запрос - приложение на сервере упало. Так я эту проблему и не решил, да ещё и расстроился, что то, что прекрасно работает в macOS, просто падает в Ubuntu, при том что и там, и там использовался Swift 3.0.1.
После этого есть какое-то чувство разочарования. Столько времени потратил, что бросать как-то не хочется.
Но одно приятное наблюдение я сделал - по сути я переписал уже сделанный ранее на Node.js API для своего приложения. API на Node.js с помощью фреймворка Restify занимает 35 мб памяти. Тот же API, написанный на Swift, у меня в macOS разогнался только до 5.2 мб памяти. На Ubuntu он стартует с 3.5 мб, но увеличивается ли потребление проверить я не смог, т.к. бинарник просто падает когда отправляешь запрос.
Вывод
Опять надо ждать новых версий Swift и новых версий фреймворков, чтобы что-то всё-таки сделать на них. К тому же, в конце октября Apple сформировали рабочую группу для развития инструментов для бэкенда, написанных на Swift, так что есть надежда. Пока писал пост ещё раз посмотрел внимательно на Vapor и очень приятно удивился. Следующим попробую именно его.
Итого:
Kitura не собирается и показал плохие результаты по производительности, но активно пилится IBM.
Perfect собирается, но то, что я написал, не работает на Ubuntu, но работает в macOS, видимо надо ждать новых версий Swift и Perfect.
Zewo отстаёт и как-то надежд на него совсем не возлагаю.
Vapor надо срочно потрогать. (Update: потрогал)
Если ваш код компилится в macOS, то не факт, что скомпилится в Ubuntu. Если работает в Ubuntu, то не факт, что будет работать, даже если работает в macOS.