Бессерверные функции — это термин, который мы часто слышим в этой отрасли, но что на самом деле означает бессерверные функции? Serverless не означает, что у вас нет серверов, это скорее серверы как услуга. Вместо того чтобы владеть и обслуживать собственные серверы, вы позволяете сервису делать работу за вас. Вы можете сосредоточиться на потребностях бизнеса и разработке более качественного приложения вместо того, чтобы беспокоиться об инфраструктуре и обслуживании традиционного сервера.
Бессерверные функции дают разработчикам суперсилу и позволяют им делать то, что иначе было бы невозможно». -Джейсон Ленгсторф
- Бессерверные функции на Netlify
- Традиционные бессерверные функции
- Плюсы
- Минусы
- Начало работы
- Настройка проекта
- Настройка проекта локально
- Netlify CLI
- Анатомия бессерверной функции
- Обзор проекта
- index.html
- netlify.toml
- Создание первой бессерверной функции
- Получение ответа
- Вызов API из бессерверной функции
- Создание новой конечной точки
- Получение конечной точки Pokédex
- Инициализация NPM
- Поддержка ESM в Node
- Установка пакетов
- Импорт пакетов
- Развертывание бессерверных функций
- Настройка запроса бессерверных функций
- Получение различных данных
- Параметры события и контекста
- Следующие шаги с бессерверными функциями
Бессерверные функции на Netlify
Бессерверные функции, которые при работе на Netlify называются Netlify Functions, — это способ развертывания кода на стороне сервера в качестве конечных точек API. Они будут автоматически запускаться при возникновении события, обрабатывать и обрабатывать код, выполняемый сервером, а затем сворачиваться до следующего события. Использование Netlify для бессерверных функций создает бесшовный рабочий процесс, который позволяет писать и тестировать функции локально с помощью Netlify CLI, создавать и развертывать приложения, а также избегать настройки, затрат и обслуживания физического сервера.
В Netlify есть несколько вариантов использования бессерверных функций. В этой статье речь пойдет о традиционных бессерверных функциях, но вы также можете изучить фоновые функции или новые граничные функции, которые могут быть распределены ближе к вашим пользователям.
Традиционные бессерверные функции
Традиционная бессерверная функция — это коротко работающая синхронная функция, написанная на JavaScript, TypeScript или Go, которая размещается в качестве конечной точки. Она выполняет некоторый код на стороне сервера, а затем немедленно возвращает ответ клиенту. Это функции AWS Lambda с регионом по умолчанию us-east-1
. Они имеют ограничение по времени в 10 секунд и ограничение по памяти в 1024 мегабайта.
Все, что мы делаем в технологии, имеет компромисс, есть плюсы и минусы, независимо от того, что это. Давайте рассмотрим оба варианта для бессерверных функций.
Плюсы
- снижает барьер входа для разработчиков
- недорогой
- быстрая итерация
- быстрое развертывание
- абстрагируется от установки и обслуживания физического сервера
Минусы
- не рассчитан на длительное выполнение процессов (ограничение 10 секунд)
- stateless — не хранит данные
- холодный старт — время, необходимое для запуска при вызове функции или эфемерных контейнеров.
Начало работы
Сейчас мы рассмотрим шаги по запуску бессерверной функции на Netlify. Чтобы начать работу с этим проектом, вам пригодится некоторое понимание HTML, JavaScript, командной строки, npm и git. Также, если у вас еще нет учетной записи Netlify, вы можете бесплатно зарегистрироваться здесь.
Настройка проекта
- Откройте репозиторий explorers up and running with serverless functions на GitHub компании Netlify.
- Нажмите кнопку Use this template, чтобы создать этот репозиторий в своем собственном аккаунте.
- Дайте своему клонированному репозиторию имя и нажмите кнопку Create repository from template.
- После создания нового репозитория нажмите кнопку Code и скопируйте ссылку для клонирования репозитория.
Настройка проекта локально
-
Откройте терминал в том месте, куда вы хотите поместить проект, затем выполните команду
git clone
и вставьте ссылку, которую вы скопировали в предыдущем шаге.git clone https://github.com/brittneypostma/new-cloned-serverless-functions-repo
-
Вы можете изменить директорию с помощью
cd
в папку вашего нового проекта прямо из терминала или открыть папку в вашем любимом редакторе кода.cd new-cloned-serverless-functions-repo
-
В настоящее время в ней находятся только файл
[README.md](http://README.md)
и.gitignore
, а также папкаpublic
.
Netlify CLI
Теперь, когда проект клонирован и настроен локально, нам нужно установить пакеты, необходимые для локального запуска бессерверных функций. Во-первых, убедитесь, что на вашей машине установлен Node.js. Вы можете проверить, установлен ли он у вас и какой версии, выполнив npm --version
. Теперь нам нужно установить интерфейс командной строки Netlify, или CLI. Выполните следующую команду в терминале, чтобы установить его глобально на вашей машине.
npm install netlify-cli --global
Вы можете использовать либо netlify
, либо сокращение ntl
для запуска команд cli. Я буду использовать сокращенную версию до конца этого руководства. Проверьте версию запущенного вами cli с помощью команды ntl --version
.
Если у вас еще нет учетной записи Netlify, вы можете бесплатно зарегистрироваться здесь. Затем вы можете войти в систему с помощью CLI, выполнив ntl login
, и авторизовать приложение.
Теперь нам нужно инициализировать приложение, выполнив ntl init
, и пройти шаги по созданию нового сайта на Netlify.
- Запустите
ntl init
и выберитеCreate & configure a new site.
.
- Выберите команду, которую вы хотите использовать.
- Назовите свой сайт или оставьте пустым для случайного имени.
- Теперь сайт создан. В терминале вы должны увидеть URL администратора, основной URL и id сайта.
- CLI запросит команду сборки, оставьте это поле пустым, и CLI заполнит
# no build command
.
- Заполните каталог для развертывания как папку
public
.
- В этом шаге оставьте папку по умолчанию
netlify/functions
.
- Поскольку мы еще не создали файл
netlify.toml
, в этом шаге введитеY
, чтобы создать его с указанными вами настройками.
- Как только вы увидите сообщение «Успех!», ваш сайт готов к развертыванию. Есть несколько следующих шагов:
git push
для запуска развертывания илиntl open
для открытия приборной панели вашего нового сайта.
Анатомия бессерверной функции
Базовая анатомия любой бессерверной функции состоит из трех основных частей. Она должна экспортировать асинхронную функцию-обработчик, а затем вернуть объект со свойством statusCode
и body
, который обычно содержит объект JSON, который необходимо преобразовать в строку с помощью метода JSON.stringify()
для чтения message
.
export const handler = async () => {
return {
statusCode: 200,
body: JSON.stringify({
message: 'This is what will be returned!'
})
}
}
Обзор проекта
Теперь, когда проект установлен локально и связан с Netlify url, мы можем начать просмотр проекта.
index.html
Откройте созданную вами директорию в вашем любимом редакторе кода и перейдите внутри публичной директории к файлу index.html
и откройте его.
Если вы посмотрите внутрь тега <body>
, вы увидите тег <h1>
, <button>
с id="fetch-btn"
и <p>
место для ответа. В теге <script>
ниже находится слушатель событий, который прослушивает нажатие на кнопку и вставляет ответ в область заполнителя.
netlify.toml
Следующий файл, на который следует обратить внимание, это файл netlify.toml
, который мы настроили с помощью Netlify CLI. Настройки сборки должны быть установлены следующим образом.
[build]
command = "# no build command"
functions = "netlify/functions"
publish = "public"
[functions]
node_bundler = "esbuild"
Директория для функций, определенных в файле toml, еще не создана. В корне проекта создайте новую папку с именем netlify и внутри нее еще одну папку с именем functions. Новая структура проекта должна выглядеть следующим образом.
Создание первой бессерверной функции
Внутри новой директории netlify/functions
создайте новый файл hello-world.js
. Используйте синтаксис export
и создайте асинхронную функцию handler
, которая возвращает statusCode
в 200 и body
с message
, которое строится с помощью метода JSON.stringify
.
export const handler = async () => {
return {
statusCode: 200,
body: JSON.stringify({
message: 'Hello World!',
}),
}
}
Получение ответа
Теперь давайте настроим JavaScript на стороне клиента, который мы будем использовать для получения ответа в файле index.html
. В теге script
под разметкой находится слушатель событий fetchBtn
, настроенный на прослушивание нажатия на кнопку в разметке. Здесь нам нужно сделать функцию async
, создать переменную для получения конечной точки serverless-функции и вернуть ответ. Следует отметить один интересный момент: когда мы получаем функцию serverless, нам нужно вызвать ее в директории .netlify
, с точкой перед ней. Это делается для того, чтобы избежать коллизии имен с другими API.
fetchBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/hello-world')
.then(response => response.json()
)
responseText.innerText = response
})
Когда функция настроена, мы можем запустить ntl dev
в консоли, чтобы запустить сервер разработки и протестировать функцию. Откройте [localhost:8888](http://localhost:8888)
в браузере, откройте консоль разработчика и перейдите на панель сети.
Когда вы нажмете на кнопку fetch, вы увидите, как вызов hello-world
появится в сетевой панели.
Вы можете увидеть состояние 200
, а если вы щелкните на функции и перейдете на вкладку Preview, вы увидите сообщение объекта «Hello World!».
Вы можете заметить, что текст печатается [объект Object]
, это потому, что нам нужно строчить ответ в функции слушателя события fetchBtn
. Добавьте метод JSON.stringify(response)
и сохраните файл.
fetchBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/hello-world')
.then(response => response.json()
)
responseText.innerText = JSON.stringify(response)
})
Если вы перезагрузите сайт и снова нажмете кнопку Fetch, теперь сообщение будет отображаться правильно.
Вызов API из бессерверной функции
Внешние API можно интегрировать с бессерверной функцией для получения данных, которые затем могут быть использованы в ответе. Мы будем работать с Poke API, который позволяет получать всевозможную информацию о мире покемонов.
Создание новой конечной точки
Вернувшись в редактор кода, нам нужно создать новый файл в каталоге netlify/functions
с именем pokedex.js
, который будет содержать нашу новую конечную точку. На этот раз создадим константу для POKE_API
url https://pokeapi.co/api/v2/pokedex/kanto
, ожидаем вызов fetch на url, создадим новую константу, data
, и ожидаем response.json()
. Далее мы вернем statusCode: 200,
и стробируем данные ответа в теле.
export const handler = async () => {
const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'
const response = await fetch(POKE_API)
const data = await response.json()
return {
statusCode: 200,
body: JSON.stringify({
data
})
}
}
Получение конечной точки Pokédex
Вернемся к файлу index.html
, сначала нам нужно добавить новую кнопку для получения конечной точки pokedex.js
, которую мы только что создали. Добавьте в разметку новую кнопку с id fetch-pokedex-btn
и текстом Fetch Pokedex.
<button id="fetch-pokedex-btn">Fetch Pokedex</button>
Далее в теге script
создайте константу и добавьте селектор элемента.
const fetchPokedexBtn = document.getElementById('fetch-pokedex-btn')
И, наконец, создайте новую функцию слушателя событий для щелчка на fetch-pokedex-btn
, чтобы добавить строковые данные в innerText
переменной, установленной в теге p
.
fetchPokedexBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/pokedex')
.then(response => response.json())
responseText.innerText = JSON.stringify(response)
})
В этот момент, если вы запустите сервер с помощью команды ntl dev
, вы увидите обе созданные нами кнопки, но кнопка Fetch Pokedex выдаст ошибку. Проверив сетевую панель и терминал на наличие проблемы, мы увидим ошибку 500 и сообщение errorMessage: "fetch is not defined"
.
Это происходит потому, что бессерверная функция, запущенная в конечной точке pokedex.js
, находится на сервере Node.JS. Node не имеет доступа к встроенному API fetch, предоставляемому в браузере. В результате нам нужно установить зависимость, которая позволит нам запустить fetch на сервере Node. Выключите сервер с помощью ctrl+C
и выполните следующие шаги, чтобы настроить серверный fetch.
Инициализация NPM
Чтобы установить пакеты внутри нашего приложения, нам нужно инициализировать его как проект npm
. Для этого запустите npm init
в корневом каталоге вашего проекта. В результате будут выполнены шаги по созданию файла package.json
. Вы можете оставить все по умолчанию, нажимая Enter
на каждом шаге, или изменить что-либо, введя это и нажав Enter
. После завершения работы, он спросит вас «Все ли в порядке?», и вы нажмете Enter
для утвердительного ответа или введете «нет», если хотите начать сначала.
Когда вы ответите «да» и нажмете Enter
, в корне вашего проекта будет создан новый файл package.json
с указанной выше информацией.
Этот файл отвечает за отслеживание любых зависимостей и некоторых основных деталей проекта.
Поддержка ESM в Node
Начиная с версии Node.js 17.0.0
, поддержка ESM, или модулей ECMAScript, стала доступна в любом приложении Node.js. Некоторые библиотеки, например, та, которую мы будем устанавливать дальше, перешли на ESM. Хотя вы можете использовать библиотеки с ESM или без него, вы не можете выбирать синтаксис, который вы используете. Вы должны полностью перевести свое приложение на ESM или придерживаться старого синтаксиса. В оригинальном видео, на котором основан этот учебник, использовался старый синтаксис для бессерверных функций. С тех пор мы обновили репозиторий, и в этом руководстве используется более новый синтаксис, поддерживаемый ESM. Чтобы перейти на ESM, добавьте "type": "module"
в файл package.json
и замените exports.handler = async function ()
на const handler = async () =>
. Если у вас есть импорты, использующие синтаксис require()
, их также необходимо преобразовать в синтаксис import name from 'package'
.
Замените синтаксис CommonJS:
const fetch = require('node-fetch')
exports.handler = async function () {
синтаксисом ESM:
import fetch from 'node-fetch'
export const handler = async () => {
Нам также нужно обновить файл netlify.toml
, чтобы указать Netlify использовать esbuild
для бессерверных функций при их развертывании. Добавьте параметр node_bundler = "esbuild"
в [functions]
.
[functions]
node_bundler = "esbuild"
Установка пакетов
Теперь, когда у нас создан файл package.json
, мы можем установить библиотеку Node fetch. В терминале выполните команду npm install --save-dev node-fetch
. После ее выполнения вы увидите новое свойство devDependencies
с библиотекой node-fetch
в файле package.json
и новый файл package-lock.json
, созданный автоматически.
Ваша версия, вероятно, будет выглядеть иначе, чем моя. Если у вас возникнут проблемы, попробуйте удалить node-fetch
командой npm rm node-fetch
, а затем установите npm install --save-dev node-fetch@3.2.8
для установки сохраненной версии.
Импорт пакетов
Вернитесь к файлу netlify/functions/pokedex.js
, где нам нужно импортировать и использовать библиотеку node-fetch
, которую мы только что установили. Нам потребуется использовать синтаксис import
, поскольку версия 3 и выше библиотеки node-fetch
использует синтаксис ESM. Добавьте эту строку в начало файла.
import fetch from 'node-fetch
Не забудьте, что вам также нужно обновить файл package.json
со свойством "type": "module"
, если вы этого еще не сделали, чтобы указать ему использовать ESM.
Теперь, если вы снова запустите сервер с помощью ntl dev
и перейдете на [localhost:8888](http://localhost:8888)
в браузере, вы увидите успешное выполнение функции.
Развертывание бессерверных функций
Ранее мы настроили и связали сайт с Netlify с помощью Netlify CLI. Каждый раз, когда мы делаем push в git-репозиторий, связанный с сайтом Netlify, автоматически запускается развертывание. Давайте выполним команды, чтобы продвинуть наш код и запустить развертывание.
- Выключите ваш сервер, если он еще не выключен, с помощью
Ctrl+C
. - Добавьте все файлы командой
git add .
, у меня 7 изменений для фиксации.
-
Зафиксируйте файлы с сообщением о том, что было изменено.
git commit -m 'Set up a Netlify site with 2 serverless functions.'
-
Отправьте изменения в git-провайдер командой
git push
илиgit push origin main
.
Этот push запустит развертывание на Netlify. Вы можете выполнить команду ntl open
, чтобы открыть панель Netlify, связанную с вашим сайтом. Там вы можете нажать непосредственно на url, чтобы открыть сайт, или перейти на вкладку Deploys, чтобы посмотреть журнал последнего развертывания.
Чтобы увидеть созданные нами бессерверные функции, перейдите на вкладку Functions.
Вы увидите 2 функции, перечисленные по имени файлов.
Далее вы можете перейти к каждой функции, чтобы увидеть время и журналы, когда они были запущены.
Настройка запроса бессерверных функций
Любая бессерверная функция может что-то делать с данными до того, как они вернутся на фронтенд. Она может быть настроена так, как вам нужно, и возвращать только то, что вы хотите использовать. В нашем примере pokedex.js
возвращает все данные о каждом покемоне и тратит место на информацию, которая нам, вероятно, не нужна. Вернитесь в файл pokedex.js
в своем редакторе кода, настройте объект data
, возвращаемый в body
, чтобы ограничить его только pokemon_entries
.
import fetch from 'node-fetch'
export const handler = async () => {
const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'
const response = await fetch(POKE_API)
const data = await response.json()
return {
statusCode: 200,
body: JSON.stringify({
pokemon: data.pokemon_entries
})
}
}
Это ограничит возвращаемые данные только списком покемонов без некоторых дополнительных данных.
Получение различных данных
Вернемся в файл index.html
, добавим еще одну кнопку и обновим нашу текущую, чтобы получить два разных типа данных. Обновите кнопку с id fetch-pokedex-btn
до id fetch-kanto-btn
. Затем добавьте новую кнопку с id feetch-hoenn-btn
.
<button id="fetch-kanto-btn">Fetch Kanto Pokedex</button>
<button id="fetch-hoenn-btn">Fetch Hoenn Pokedex</button>
Нам также потребуется обновить переменные и функции в теге script. Замените строку fetchPokedexBtn
новыми переменными, которые получат новые идентификаторы.
const fetchKantoBtn = document.getElementById('fetch-kanto-btn')
const fetchHoennBtn = document.getElementById('fetch-hoenn-btn')
Далее нам нужно обновить функции слушателя событий для захвата различных типов данных. Во-первых, измените имя текущего слушателя событий fetchPokedexBtn
на fetchKantoBtn
. Теперь мы можем редактировать возвращаемые данные, используя родной fetch API, который принимает объект options в качестве второго параметра, чтобы передать метод POST
и отправить пользовательские данные обратно в бессерверную функцию. Здесь мы хотим указать регион kanto для API Pokémon.
fetchKantoBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/pokedex', {
method: 'POST',
body: JSON.stringify({
region: 'kanto'
})
})
.then(response => response.json())
responseText.innerText = JSON.stringify(response)
})fetchKantoBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/pokedex', {
method: 'POST',
body: JSON.stringify({
region: 'kanto'
})
})
.then(response => response.json())
responseText.innerText = JSON.stringify(response)
})
Нам также нужна функция слушателя событий для кнопки «Fetch Hoenn Pokedex». Мы сделаем то же самое, но заменим регион kanto
на hoenn
.
fetchHoennBtn.addEventListener('click', async () => {
const response = await fetch('/.netlify/functions/pokedex', {
method: 'POST',
body: JSON.stringify({
region: 'hoenn'
})
})
.then(response => response.json())
responseText.innerText = JSON.stringify(response)
})
Параметры события и контекста
Все функции serverless принимают два параметра, event
и context
. Объект event
включает информацию о запросе, а параметр context
— информацию о контексте, в котором была вызвана функция. Мы можем использовать объект event
для получения пользовательских заголовков, которые мы отправляем вместе с запросами, добавленными в код index.html
. В файле pokedex.js
добавьте два параметра в функцию обработчика и запишите событие и контекст в журнал console.log(event, context)
Мне нравится оборачивать переменные, которые я записываю в журнал, в объект {}
, чтобы видеть имя, когда оно приходит.
// pokedex.js
import fetch from 'node-fetch'
export const handler = async (event, context) => {
console.log({event}, {context})
const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto'
const response = await fetch(POKE_API)
const data = await response.json()
return {
statusCode: 200,
body: JSON.stringify({
pokemon: data.pokemon_entries
})
}
}
Сохраните файл и запустите ntl dev
, нажмите на одну из кнопок Fetch Kanto Pokedex, и в терминале вы увидите множество данных, приходящих обратно. Важной частью здесь является event.body
, который, как вы увидите, является регионом покемона, которого мы отправили через метод POST
.
Мы будем использовать эту информацию, создав переменную для хранения разобранного event.body
и затем обновим url, который будет динамически обновляться в зависимости от отправленного региона.
import fetch from 'node-fetch'
export const handler = async (event, context) => {
const eventBody = JSON.parse(event.body)
const POKE_API = 'https://pokeapi.co/api/v2/pokedex/kanto' + eventBody.region
const response = await fetch(POKE_API)
const data = await response.json()
return {
statusCode: 200,
body: JSON.stringify({
pokemon: data.pokemon_entries
})
}
}
Теперь, если вы обновите страницу и нажмете две кнопки Pokedex, вы увидите два отдельных набора данных, основанных на указанном регионе. Вы можете добавить, зафиксировать и выложить свой код в git, чтобы начать новое развертывание сайта.
Следующие шаги с бессерверными функциями
Отличная работа! Вы узнали, как бессерверные функции могут дать разработчикам суперсилу для создания и настройки функциональности в своих приложениях. Это позволяет решать бизнес-задачи с помощью более широкого спектра инструментов и методов без необходимости управлять какой-либо инфраструктурой. Теперь перед вами открылось целое царство возможностей, которые можно исследовать с помощью бессерверных функций. Чтобы узнать больше о том, как получить максимальную отдачу от бессерверных функций с Netlify, обязательно ознакомьтесь с официальной документацией, где вы можете узнать больше о других решениях, таких как фоновые функции, которые позволяют выполнять длительные сценарии, используя бессерверные методы. Мне не терпится увидеть, что вы создадите с помощью функций Netlify. Помните, если ваш опыт отличается от того, что написано здесь, или что-то работает не так, как ожидалось, пожалуйста, сообщите нам об этом здесь, и мы поможем вам или ответим на любые ваши вопросы.