express.lua – создание веб приложений на Lua
🌕 express.lua это самый детализированный порт оригинального express.js, написанный на Lua. Пока кто-то не докажет обратного.
По сути, lua-express
это минималистичный web фреймворк с почти полной совместимостью API с express.js
, позволяющий создавать веб приложения на чистом Lua.
- express.js
- express.lua
const express = require("express")
const app = express()
app.get("/", function(req, res) {
res.send("Hello World")
})
app.listen(3000)
local express = require("express")
local app = express()
app:get("/", function(req, res)
res:send("Hello World")
end)
app:listen(3000)
Изначально идея создания этого порта появилась из-за желания отделить API одного сервиса с монолитного PHP приложения в отдельный микросервис, чтобы при атаках его было проще масштабировать.
Сейчас цель достигнута – express.lua работает в продакшене, API сервиса переписан и прямо сейчас успешно обрабатывает запросы, причем также асинхронно работая с mysql и redis (покликайте) без каких-либо крупных зависимостей, используя только copas и luasocket для асинхронности и связи с базами данных соответственно. Раньше такого в "чистом" Lua еще никто не делал. Решений просто не существовало.
Немного бекстейджа
На первую рабочую версию lua-express ушло несколько недель, несмотря на небольшую базу кода. Дело в том, что express.js построен на базе nodejs, но у Lua полноценного И МИНИМАЛИСТИЧНОГО nodejs (по сути, встроенного веб сервера) просто не существовало.
Второй глобальной проблемой являлось то, что Lua привыкли рассматривать, как что-то, где асинхронности не существует, что означало бы, что один медленный запрос остановил бы все последующие. Поэтому перед созданием порта пришлось очень плотно изучить как делать штуки в lua "асинхронными". В кавычках, потому что Lua все же однопоточный ЯП, поэтому вместо настоящей асинхронности мы имеем крутой хак с сокетами и корутинами. Думаю, что на самом деле в JS все устроено так же, только Lua показал себя более производительным в бенчмарках на одинаковых задачах*.
* к сожалению, не в вопросах работы с сокетами
🤔 В итоге, что мы сейчас имеем?
Действительно полноценный express.js прямо в Lua, который работает, работает хорошо, работает на более простом (имхо), но производительном Lua, он не требует никаких openresty зависимостей, легко встраивается в любое готовое приложение (например, в телеграм боты, написанные на lua)
🌈 Преимущества:
- Не требует больших зависимостей. Например, lapis требует целый openresty.
- За основу взят express.js, который известен по всему м иру своей простотой, гибкостью и производительностью.
- Для тех, кто работал с express.js будет очень легко понять и перейти на express.lua – API почти на 100% идентичен.
- Все входящие запросы можно обрабатывать асинхронно (non-blocking), использая copas. Это тысячи запросов в секунду.
- Легко встраивать в скрипты и приложения любой сложности. lua-express легенький и из "сложного" требует только luasocket.
- Прошел проверку боем. Используется в реальном приложении и приносит счастье.
🤔 Где взять, как установить?
Информацию по этому поводу искать в репозитории lua-express.
Если какой-то информации там не хватает, то можете создать Issue (я постоянно слежу за Issues), либо написать мне (внизу написано как) и я допишу все, что может потребоваться.
🖼️ Примеры
Для тех, кто использовал express – примером может быть любое написанное вами на express.js приложение. Lua версия будет отличаться лишь незначительно.
Если про express.js вы только слышали (не слышать о нем невозможно), то пример можете посмотреть тут: клик. Более продвинутый: тут
Примеры реализаций на Lua можно посмотреть в /examples репозитория lua-express.
👉 А вот тут можно посмотреть пример реализации long-polling
сервера. Я использую его как единую точку сбора вебхуков со всех сервисов (github webhooks, telegram, luadev переписал на вебхуки, healthcheck, VK webhooks), затем с этого одного места забираю апдейты сразу с множеством микросервисов (например разные части одного телеграм бота работают как отдельные микросервисы на разных серверах). Здесь есть пост в блоге.
P.S.
-
Мне очень нравится как в express устроены роутинги, поэтому если вы еще ими не пользовались или не знаете что это, то советую разобраться. Они позволяют "прикреплять" пути к определенному префиксу, а у префикса могут быть свои middlewares. Они значительно упрощают код и позволяют с легкостью масштабировать код приложения с минимальными изменениями. Условно, вы начали писать приложение чисто, как /api, но решили добавить /admin.. короче.. Роутеры в express это круто.
-
Порт настолько детальный, что даже фишечка express с error handler middleware тоже была перенесена. Обычные мидлы выглядят вот так: (req, res, next), а с ошибкой вот так: (err, req, res, next). Т.е. если указано 4 параметра, то мидлвер будет считаться обработчиком ошибок, а не обычным мидлвером. Вот, смотрите. Красивое.