Netlify Functions を使って最速でサーバーを作る


# はじめに

サーバーレスのサービスといえば

- Cloud Functions for Firebase
- AWS Lambda
- Azure Functions

など、ビッグテックが提供するこれらの機能が有名です。基本的には無料枠があるので簡単に使えますが、'**クレジット登録が必須**' で業務上で手軽に試すには少し問題がありました。

そこで `Heroku` を検討しましたが、`Heroku` は使用していないとスリープ状態になってしまいます。数秒〜数十秒の差で、裏側が `AWS Lambda` である `Netlify Functions` の方が早いと判断して、こちらを試してみました。

# Netlify Functions とは？

https://www.netlify.com/

> Netlify is the essential platform for the delivery of exceptional and dynamic web experiences, without limitations.

静的ページを公開するには最適のサービスで、そんな `Netlify` の機能として `Netlify Functions` というサーバレスの機能です。

https://docs.netlify.com/functions/overview/

現在は、TypeScript, JavaScript, Go での開発が可能です。（2024/07 時点）

# Netlify Functions でサーバーを作る

## 0. 試す前に

基本的には、以下の記事を元に進めました。

https://zenn.dev/amay077/articles/206e4bcd691bdf

ただ、情報が少し変わっており引っかかる点がありました。

また、公式のドキュメントを読んだ結果、この記事よりも少ない設定で試せることがわかったので、そちらを記載しようと思います。

https://docs.netlify.com/

## 1. アカウント登録

サクッとアカウントを作りましょう。

https://app.netlify.com/signup

以下のサービスを使ってサインアップも可能です。

- GitHub
- GitLab
- Bitbucket

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/911441b1-4af9-b935-7cda-0acc316b2359.png)

## 2. ファイルの準備

デプロイするコードを用意します。今回は最も簡単な `"Hello World"` を返す API を作ります。

```.js
exports.handler = async function(event, context) {
    return {
        statusCode: 200,
        body: JSON.stringify({ message: "Hello World" })
    };
};
```

次にディレクトリ構成を作ります。`Functions` を動かす最も少ない構成はこれだけです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/677a8e5f-27fc-63a1-ff9f-b9eb7bbd0637.png)

このディレクトリがデフォルトで予約されている構成になっています。

-> **`netlify > functions > .js`**

今回は `JavaScript`（Node） で行っていますが、`netlify > functions` 配下に実行したいコードを配置すれば良いので、他の言語でも同様です。また、ファイル名は任意なもので問題ないです。あとで**実行するときのパス**になります。

## 3. コードのデプロイ

いくつかの `Netlify` 記事（2024年より前）ではメニューが上にある UI が散見されます。現在は左側にメニューがあります。

`Sites` から `Netlify` にコードを反映します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/bb733f0a-7d26-4526-68c9-b351058a0cea.png)

この画面では３つの選択肢があります。

- Git で管理するコード
- Netlify が用意したテンプレート
- 手動アップロード（ローカルPCからファイル参照）

テンプレートは、あくまでも WEB サイトのテンプレートなので、`Functions` を使いたい場合は、少しオーバーかもしれません。

また、これとは別に `Netlify CLI` を使って、ローカルPCからアップロードもできます。

https://docs.netlify.com/cli/get-started/

ここで１点だけ...

:::note warn
注意
手動でのアップロードでは `Functions` が機能しない
:::

これにハマってかなり戸惑いました。
（諸事情により Git や CLI を使えず手動のアプローチを試みていた）

手動でアップロードした場合、`HTML` は認識されて静的なサイトは反映できましたが、`Functions` は機能しませんでした。`Git` or `CLI` でコードをアップロードしましょう。

記載していませんでしたが、`Git` 管理下のものを連携する際はリポジトリの指定が必要なので、あらかじめリポジトリを作成して、コードをリモートにアップロードしておきましょう。

## 4. ステータスの確認

アップロードをすると、`Deploy` タブからデプロイ中のものを確認できます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/9f63aef3-300a-f769-45af-41a114d0cbad.png)


`function deployed` となっていれば、ちゃんとコードが認識されています。

生成された 'ユニークなID' が仮のパスになります。別途、DNS を設定することもできます。

https://docs.netlify.com/domains-https/netlify-dns/

## 5. API を試してみる

先ほどデプロイされたものにある 'ユニークなID' を使います。また、ディレクトリ構成を変えていなければ、実行できるパスは以下のようになります。

`curl -X GET 'https://YOUR_APP_ID.netlify.app/.netlify/functions/index'`

実際に実行してみると

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/1fcf4205-222d-ab49-550f-f95c493562d3.png)

このように結果が返ってきました。
簡単でしたね！

# Netlify の機能を試す

いくつかおまけ程度に載せておきます。

## - 静的な WEB ページを表示する

### ① ルートに WEB ページを表示する

最低限 `Hello, World!`を表示する `HTML` を用意します。

```.html
<!DOCTYPE html>
<html>
<body>
    Hello, World!
</body>
</html>
```

それをディレクトリのルートに設置します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/87612b2f-bc66-97fb-d277-25b9680b6e85.png)

あとはデプロイすれば、そのままルートのパスで表示されます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/5ec3eb49-aee0-69a0-f80a-c147cd386330.png)

### ② サブディレクトリで WEB ページを表示する

設置したパスにアクセスすればそのまま表示されます。

同じように `HTML` を用意して

```.html
<!DOCTYPE html>
<html>
<body>
    sub
</body>
</html>
```

任意のパスに設置します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/dd350980-0d43-9971-bd3c-79fbb29bd176.png)

デプロイした後はそこにアクセスするだけです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/b71e5586-038d-f17d-9fcf-46dc6cf137ad.png)


## - ディレクトリ構成を変える

今回は Functions 向けにフォーカスします。上でも記載しましたが Functions では `netlify > functions` が関数のデフォルトのパスです。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/5cc2a029-2355-1161-b24c-f72905656509.png)
（引用: [公式サイト](https://docs.netlify.com/configure-builds/file-based-configuration/#functions)）

ビルドの設定など、多くのデフォルト値は変更可能です。

<br>

ただし...

:::note warn
注意
こちら記事にしていますが、手元では設定を反映できなかったので注意してください（できた方はコメントください...）
:::

以下、公式サイトのドキュメント通りに試してみたものを残しておきます。


### 方法① GUI 上で設定する

<details><summary>詳細を見る</summary>

手軽な方法は GUI 上での設定です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/0dc7357f-251a-0473-7e8d-f4abf3d17fe8.png)

ただし、次の方法で設定ファイルがある場合は、GUI の設定は上書きされます。
</details>


### 方法② `netlify.toml` から設定する

<details><summary>詳細を見る</summary>

設定ファイル（`netlify.toml`）を **ルートディレクトリ直下** に設置します。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/6a0273db-a891-cc42-e83f-d4b2a20e9afa.png)

以下のようにパスを設定します。

```.toml
[functions]
  directory = "netlify/zzz/vvv/"
```

公式のドキュメントを見ると多くの設定方法が記載あります。
-> https://docs.netlify.com/configure-builds/file-based-configuration/

</details>

## - Functions に CORS 対応する

サーバーとして使う場合は `netlify.toml` に設定すれば良いのですが、Functions では別の設定が必要です。

https://qiita.com/hitochan777/items/8f1c4d2309fb8ea90a1c

裏側が `AWS Lambda` であることを利用して、SDK をそのまま使ってしまうのが早いです。以下は JavaScript（Node）の実装を行う場合です。

### ① `netlify.toml` の設定を追加

Node のパッケージを入れるために、デプロイ時にビルドするようコマンドを追加します。

```.toml
[build]
  command = "npm run build"
```

### ② パッケージの設定

AWS の SDK を追加します。

```.json
{
  "name": "netlify-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "echo \"No build step\""
  },
  "dependencies": {
    "aws-sdk": "^2.1045.0"
  }
}
```

これは例なので、必要に合わせて修正してください。

作成したパッケージをルートに設定してください。構成はこのような形です。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/7cc43416-5f85-0533-b294-282a55bf36ea.png)

ちなみに、AWS にしましたが、Express など他のライブラリでも出来ると思います。

### ③ CORS 対応コードを JS に入れる

`Hello World` を返すだけの処理を作ります。

```.js
const AWS = require('aws-sdk');

exports.handler = async (event) => {
  const response = {
    statusCode: 200,
    headers: {
      'Access-Control-Allow-Origin': '*',
    },
    body: JSON.stringify({ message: 'Hello World' }),
  };

  return response;
};
```

`'Access-Control-Allow-Origin': '*'` で無効にしています。

実際に WEB のコンソールから実行して見ると、結果が返ってきます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/a4c17fc1-8548-c7ad-4faf-aea02a95f74f.png)

無事に CORS を回避できました！

# 終わりに

クレカいらずで出来るのは嬉しいですね！

最近（2024年）に UI 含め大きくアップデートがあったようで、情報の古いものが多かったです。またドキュメントを参照しても動かないものもあったので、少しだけ手こずりましたが、他のサーバーレスに比べると、比較的手軽に操作できるのは嬉しいなポイントです。