Netlify Functionsを使ってクエリを返す関数を作成しよう【Nuxt.js×TypeScript】
  • 2022.02.13に公開
  • ブログ構築TS
  • 8. NetlifyFunctionsを使った検索機能
  • No.1 / 9

今回達成すること

このチャプターで実装する「ブログ検索機能」には、Netlify Functionsを使用します。

この記事では、Nerlity Functionsのインストールとセットアップ、そしてクエリを返すテスト関数を作成し、ローカルサーバーで実行します。

ブログ検索機能を実装するには?

検索機能を実行するには、ユーザーが入力した検索キーワードを持って、Contentful APIへリクエストを行います。

NuxtからContentful APIへリクエストを行うと、フロントからリクエストを行う必要があり、API KeyをJavaScriptに登録しなければなりません。

JavaScriptにAPI Keyを登録すると、ここでお伝えした通りKeyが漏洩します。

API Keyの漏洩を防ぐ検索機能の実装方法

API Keyの漏洩を防ぐには、

  • フロントで入力された検索キーワードを
  • axiosモジュールでNetlify Functionsに渡し、
  • サーバーサイドからContentful APIへリクエストを行う必要があります。

上記の実装で、JavaScriptにAPI Keyを登録しなくてもAPIリクエストを行うことができます。

Netlify Functionsとは?

Netlify Functionsとは、JavaScriptの関数によってサーバーを操作する、Netlifyが用意している機能です。2022年2月現在、Go言語も使用可能です。

Documents: Functions overview | Netlify Docs

料金

Netlify Functionsの料金はリクエスト数によって課金されます。

無料プランでは、月リクエスト数が125,000回まで無料、超過した場合は$25が課金されます。

Starter(無料) Pro($19/月) Business($99/月)
Serverless FunctionsInvocations 125k per site /month
($25+ when exceeded)
125k per site /month
($25+ when exceeded)
Unlimited

最新の料金は下記URLよりご確認ください。

Netlify Pricing and Plans

前提条件

Netlify Functionsを実行するには、netlifyコマンドが使用できる環境が必要です。

上記コマンドを使用するには、netlify-cliをインストールします。

% yarn add --dev netlify-cli

既にインストール済みの方は実行しないでください。

インストール

Netlify Functionsを使用するには、@netlify/functionsモジュールをインストールします。

% yarn add @netlify/functions

下記で手順に沿ってインストールするので、まだ実行しないでください。

Functionsプロジェクトの作成

Netlifyが用意しているfunctions:createコマンドでFunctionsを操作するプロジェクトを作成することができます。

作成されるプロジェクトにJavaScriptの関数を記述します。

% yarn netlify functions:create

下記で手順に沿って作成するので、まだ実行しないでください。

Functionsプロジェクトの置き場所

今回は「netlify」ディレクトリを作成し、その中でNetlify Functionsのセットアップを行います。

「netlify」ディレクトリは、Functionsを扱うための別アプリだとお考えください。

package.jsonも別に作成するため、Functions内では、Nuxtでインストールしたモジュールを使用することはできません。

Netlify Functionsのインストールとセットアップ

作業に入る前にブランチを切っておきましょう。

% git checkout -b 20220211_netlify_functions
% git branch
* 20220211_netlify_functions

Functionsを扱う「netlify」ディレクトリを作成し、その直下にpackage.jsonを作成します。

% mkdir netlify && touch $_/package.json

package.jsonのセットアップ

作成したpackage.jsonのセットアップを行います。

netlify/package.json
{
  "name": "<アプリ名>_functions",
  "version": "1.0.0",
  "private": true,
  "scripts": {},
  "dependencies": {},
  "devDependencies": {}
}
  • "<アプリ名>_functions" ... Nuxtルートディレクトリ直下にあるpackage.jsonnameの値をアプリ名に入力する。

@netlify/functionsのインストール

Functionsを扱うための@netlify/functionsモジュールを、「netlifyディレクトリ以下にインストールします。

% cd netlify
netlify % yarn add @netlify/functions

netlify.tomlのセットアップ

netlify.tomlには、Netlifyが参照するFunctionsのディレクトリを指定します。

デフォルトの参照パスは「netlify/functions」なので、今回の設計では指定しなくても良いですが、明示的に指定しています。

The default location is YOUR_BASE_DIRECTORY/netlify/functions.

引用: File-based configuration | Netlify Docs

netlify.toml
# Doc: https://docs.netlify.com/configure-builds/file-based-configuration/
# ビルド設定
[build]
  # 公開ディレクトリ
  publish = "dist"
  # 実行コマンド(target: 'static')
  command = "yarn generate"

[functions]
  # netlify functionsコマンドが参照するディレクトリパスを指定(default: YOUR_BASE_DIRECTORY/netlify/functions)
  # [build]のbaseディレクトリが指定されている場合はそこからの相対パスとなる(default: base = "/")
  directory = "netlify/functions"
  • "netlify/functions" ... 「functions」ディレクトリはfunctions:createコマンドが自動生成してくれるので作成しなくて良い。

注意)functionsディレクトリをルート直下に置く場合

Functionsプロジェクトをルート直下の「functions」ディレクトリに作成する場合、functions:createコマンドはルート直下のpackage.jsonを使用します。

この時、typescriptが自動でインストールされます。

この場合、Nuxtがインストールしたtypescriptと競合になるため、yarn devコマンドが正常に動きません。

  • 必ず、別のpackage.json@netlify/functionsをインストールし、
  • netlify functionsコマンドは、
    • そのpackage.jsonが置かれたディレクトリ内の
    • 「functions」ディレクトリを参照するように設定してください。

今回のFunctionsプロジェクトの設計

  • @netlify/functionsのインストール先 => netlify/package.json
  • netlify functionsコマンドが参照するディレクトリ => 「netlify/functions」

これにより、functions:createコマンドを実行したときに、netlify/package.jsontypescriptがインストールされます。

Functionsプロジェクトを作成する

ルートディレクトリからfunctions:createコマンドを実行します。

% yarn netlify functions:create

# 使用言語はTypeScriptを選択 Enter
? Select the language of your function 
  JavaScript 
❯ TypeScript 
  Go 

# 作成するテンプレートは「hello-world」を選択 Enter
? Pick a template 
❯ [hello-world] Basic function that shows async/await usage, and response formatting
  ──────────────
  Clone template from GitHub URL 
  Report issue with, or suggest a new template 
  ──────────────

# プロジェクト名はhello-world そのままEnter
? Name your function: (hello-world) 

# プロジェクト作成完了
 Installed dependencies for hello-world
✨  Done in 191.18s.

これでFucntionsのhello-worldプロジェクトが作成できました。

現在の「netlify」ディレクトリは以下の構造になっています。

netlify
├── functions
│   └── hello-world
│       └── hello-world.ts
├── node_modules
├── package-lock.json
├── package.json
└── yarn.lock

package.jsonの中身は最終的に以下のようになります。

netlify/package.json
{
  "name": "demo_blog_v2_functions",
  "version": "1.0.0",
  "private": true,
  "scripts": {},
  "dependencies": {
    "@netlify/functions": "^0.11.0",
    "@types/node": "^14.18.11",
    "typescript": "^4.5.5"
  }
}

Functionsのプロジェクト名はURLになる

Functionsのプロジェクト名というのは「functions」直下のディレクトリ名です。

プロジェクト名は、関数にアクセスするためのURLとなるので、-で繋ぐケバブケースで作成することを推奨します。

hello-world.tsを改修する

自動で作成されたhello-world.ts内のコードでは、タイプエラーが発生します。

そこでコードを改修し、クエリを取得する関数に書き換えます。

netlify/functions/hello-world/hello-world.ts
import { Handler } from '@netlify/functions'

// any型の追加, _contextへの書き換え
export const handler: Handler = async (event: any, _context: any) => {
  // 追加
  const query: string = await event.queryStringParameters.q || 'No query'

  return {
    statusCode: 200,
    body: JSON.stringify({
      // queryに書き換え
      message: `Hello, ${query}!`
    })
  }
}
  • event.queryStringParameters ... 関数にアクセスするURLのクエリを取得するプロパティ。URLクエリが?q=aaaの場合は、{ q: 'aaa' }のオブジェクトを返す。

Functionsを動かそう

ローカル環境でFunctionsプロジェクトを動かすには、Functionsのサーバーを起動する必要があります。

Functionsサーバーを起動するには、functions:serveコマンドを実行します。

% yarn netlify functions:serve

◈ Injected .env file env var: CTF_SPACE_ID
◈ Injected .env file env var: CTF_DELIVERY_API_KEY
◈ Injected .env file env var: CTF_PREVIEW_API_KEY
◈ Injected .env file env var: APP_NAME
◈ Injected .env file env var: APP_EMAIL
◈ Loaded function hello-world (http://localhost:undefined/.netlify/functions/hello-world).
◈ Functions server is listening on 9999

ローカルFunctionsサーバーにアクセスするURLは、http://localhost:9999となります。

Functions関数を実行する

関数を実行するには、プロジェクト毎に生成されたルートへアクセスします。

  • http://localhost:9999/.netlify/functions/hello-world

2022-02-11 19-18-11

クエリを取得できているか確認してみましょう。

  • http://localhost:9999/.netlify/functions/hello-world?q=test

2022-02-11 19-20-45

関数が正しく実行され、クエリを表示することができました。

コマンドでFunctions関数を確認する

コマンドでも関数の実行を確認することができます。

サーバーを起動した状態で、functions:invoke <プロジェクト名>を実行してください。

% yarn netlify functions:invoke hello-world --port 9999

# NetlifyのID認証ヘッダをエミュレートして呼び出すか? => Yを入力
? Invoke with emulated Netlify Identity authentication headers? (pass --identity/--no-identity to override) (Y/n) Y

{"message":"Hello, No query!"}
  • --port 9999 ... invokeコマンドはデフォルトでポート8888を参照する。Functionsサーバーは9999で起動しているので、サーバーのポート番号を指定する。

Functionsサーバーのポートを変更する

functions:invokeコマンドは、デフォルトで8888のポート番号を参照します。

そこで、Functionsサーバーのデフォルトポート番号を8888に変更します。

netlify.toml[dev]を追加しましょう。

netlify.toml
# Doc: https://docs.netlify.com/configure-builds/file-based-configuration/
# ビルド設定
[build]
  # 公開ディレクトリ
  publish = "dist"
  # 実行コマンド(target: 'static')
  command = "yarn generate"

[functions]
  # netlify functionsコマンドが参照するディレクトリパスを指定(default: YOUR_BASE_DIRECTORY/netlify/functions)
  # [build]のbaseディレクトリが指定されている場合はそこからの相対パスとなる(default: base = "/")
  directory = "netlify/functions"

[dev]
  # functions:serveで起動するポート番号の指定(default: 9999)
  functionsPort = 8888

もう一度Functionsサーバーを起動します。

% yarn netlify functions:serve

Functions server is listening on 8888

これで、functions:invokeコマンドに--portオプションを付与しなくて良くなります。

% yarn netlify functions:invoke hello-world

{"message":"Hello, No query!"}

今回の作業は以上です。

% git add -A
% git commit -m "Setup Netlify Functions" -m "Add Functins project for hello-world"

まとめと次回

今回は、「netlify」ディレクトリ以下にNetlify Functionsのセットアップを行いました。

そしてクエリを返すhello-worldプロジェクトを作成しました。

次回は、このプロジェクトを本番環境のNetlify Functionsにデプロイします。

あなたの力になれること
私自身が独学でプログラミングを勉強してきたので、一人で学び続ける苦しみは痛いほど分かります。そこで、当時の私がこんなのあったら良いのにな、と思っていたサービスを立ち上げました。周りに質問できる人がいない、答えの調べ方が分からない、ここを聞きたいだけなのにスクールは高額すぎる。そんな方に向けた単発・短期間メンターサービスを行っています。
独学プログラマのサービス
ブログ構築TSの投稿
1
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #01
Nuxt.jsをローカルPCに立ち上げよう
2
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #02
Nuxt.jsプロジェクトをGitHubにPushしよう
3
  • Nuxt.js×TypeScript開発環境構築
  • /
  • #03
nuxt-property-decoratorのインストールとTypeScriptのセットアップ
1
  • Vuetifyセットアップ
  • /
  • #01
TypeScript環境のNuxt.jsにVuetifyを導入しよう
2
  • Vuetifyセットアップ
  • /
  • #02
VuetifyにカスタムCSSを追加してSASS変数を理解しよう
3
  • Vuetifyセットアップ
  • /
  • #03
VuetifyにカスタムSVGアイコンを追加しよう
1
  • NetlifyCLIを使ったNuxtデプロイ
  • /
  • #01
Netlify CLIをインストールして本番環境のサイトを作成しよう
2
  • NetlifyCLIを使ったNuxtデプロイ
  • /
  • #02
netlify.tomlを使ってNuxt.jsをNetlifyに手動デプロイしよう
1
  • Contentfulモデル構築
  • /
  • #01
Contentfulの料金とCommunityプランの無料枠を理解する
2
  • Contentfulモデル構築
  • /
  • #02
Contentfulへ新規会員登録、ロケールの変更、API Keyの発行を行う
3
  • Contentfulモデル構築
  • /
  • #03
Contentful ブログカテゴリーモデルを作成しよう
4
  • Contentfulモデル構築
  • /
  • #04
Contentful カテゴリーモデルに1対1で関連づくblogPostモデルを作成しよう
5
  • Contentfulモデル構築
  • /
  • #05
Contentful ブログ記事に1対多で関連づくplogTagモデルを作成しよう
6
  • Contentfulモデル構築
  • /
  • #06
Contentful カテゴリー・ブログ記事・タグコンテンツを作成しよう
1
  • Nuxt.js×Contentfulセットアップ
  • /
  • #01
Nuxt.js×Contentfulセットアップ。モジュールのインストールからAPI Keyの登録まで
2
  • Nuxt.js×Contentfulセットアップ
  • /
  • #02
Contentful APIリクエストの実行 Nuxt.jsにブログコンテンツを表示しよう
3
  • Nuxt.js×Contentfulセットアップ
  • /
  • #03
ContentfulAPIをNetlifyにデプロイしよう【Nuxt FullStaticのasyncDataとfetch】
1
  • Vuex×TypeScriptセットアップ
  • /
  • #01
Vuexの型付け vuex-module-decoratorsとnuxt-typed-vuexどちらを使用するか
2
  • Vuex×TypeScriptセットアップ
  • /
  • #02
nuxt-typed-vuexのインストールとセットアップ。Vuexの型定義と呼び出し方
3
  • Vuex×TypeScriptセットアップ
  • /
  • #03
VuexにContentfulの型定義ファイルとnuxtServerInitを追加しよう
4
  • Vuex×TypeScriptセットアップ
  • /
  • #04
VuexにContentfulAPIレスポンスを保存してVueファイルに表示しよう
1
  • コンテンツページ構築
  • /
  • #01
ブログアプリのページ設計とNuxt.jsの動的ルーティングについて理解しよう
2
  • コンテンツページ構築
  • /
  • #02
カテゴリーのコンテンツページを作成しよう【Nuxt.js×Contentful】
3
  • コンテンツページ構築
  • /
  • #03
カテゴリーに関連付くブログ記事一覧を表示しよう【Nuxt.js×Contentful】
4
  • コンテンツページ構築
  • /
  • #04
injectを使用して共通エラー処理メソッドを作成しよう【Nuxt×TypeScript】
5
  • コンテンツページ構築
  • /
  • #05
NuxtChildを使用してブログ記事ページを作成しよう【Nuxt.js×TypeScript】
6
  • コンテンツページ構築
  • /
  • #06
タグ一覧ページとタグ関連づく記事一覧を表示しよう【Nuxt.js×TypeScript】
7
  • コンテンツページ構築
  • /
  • #07
プライバシーポリシーページを作成しよう【Nuxt.js×TypeScript】
8
  • コンテンツページ構築
  • /
  • #08
@nuxtjs/i18nのインストールとセットアップ。ページタイトルの翻訳化【TypeScript】
1
  • NetlifyFunctionsを使った検索機能
  • /
  • #01
Netlify Functionsを使ってクエリを返す関数を作成しよう【Nuxt.js×TypeScript】
2
  • NetlifyFunctionsを使った検索機能
  • /
  • #02
Netlify Functionsプロジェクトをデプロイしよう【Nuxt.js×TypeScript】
3
  • NetlifyFunctionsを使った検索機能
  • /
  • #03
Nuxt.js × axiosセットアップ Netlify Functionsにリクエストを行う準備をしよう
4
  • NetlifyFunctionsを使った検索機能
  • /
  • #04
オリジン•CORS•プリフライトリクエストを理解する【Nuxt.js×Netlify Functions】
5
  • NetlifyFunctionsを使った検索機能
  • /
  • #05
Netlify Functionsを使ってフォームバリデーション機能を構築しよう【Nuxt.js】
6
  • NetlifyFunctionsを使った検索機能
  • /
  • #06
ツールバーに表示する検索フォームを作成しよう【Nuxt.js×TypeScript】
7
  • NetlifyFunctionsを使った検索機能
  • /
  • #07
検索ページを作成しよう【Vue propsとTypeScriptの書き方 解説】
8
  • NetlifyFunctionsを使った検索機能
  • /
  • #08
Netlify FunctionsからContentfulAPIリクエストを送ろう【Nuxt.js】
9
  • NetlifyFunctionsを使った検索機能
  • /
  • #09
検索ページに「もっと見る」ボタンを実装しよう【Nuxt.js×TypeScript】
1
  • ブログMarkdown対応
  • /
  • #01
@nuxtjs/markdownitのインストールとセットアップ【Nuxt.js×TypeScript】
2
  • ブログMarkdown対応
  • /
  • #02
Nuxt.js×markdown-it 外部リンクを別タブで開くプラグインを追加しよう
3
  • ブログMarkdown対応
  • /
  • #03
Nuxt.js×markdown-it 内部リンクをVueRouterで高速にページ遷移しよう
4
  • ブログMarkdown対応
  • /
  • #04
Nuxt.js×markdown-it アンカーリンクとブログ目次を自動生成しよう
独学プログラマ
独学でも、ここまでできるってよ。
CONTACT
Nuxt.js制作のご依頼は下記メールアドレスまでお送りください。