Guides

アプリケーションサービス

Effect のサービスで、アプリケーションの処理と依存関係を構成するためのガイド。

Effect のサービスを使うと、アプリケーションのロジックを、それを呼び出す Page から分離できます。 挨拶を返す例では、実装を差し替えられるサービスを Page に提供し、その実装と生存期間を Effect の Layer で管理します。

Page でサービスを使う

src/greeting.ts を作成します。

import { Context, Effect, Layer } from "effect";

export class Greeting extends Context.Service<
  Greeting,
  { readonly message: (name: string) => Effect.Effect<string> }
>()("app/services/Greeting") {
  static readonly layer = Layer.succeed(Greeting, {
    message: (name) => Effect.succeed(`Hello, ${name}.`),
  });
}

src/entry.effront.tsx で Greeting を宣言し、Page から読み取り、その Layer を提供します。

// src/entry.effront.tsx: add to the imports.
import { Greeting } from "./greeting";

// Replace EFFRONT.
const EFFRONT = Application.effront<Greeting>();

// Replace HomePage.
const HomePage = EFFRONT.Page.make({
  render: Effect.fn("HomePage.render")(function* () {
    const greeting = yield* Greeting;
    const message = yield* greeting.message("Ada");
    return <h1>{message}</h1>;
  }),
});

// Replace the default export with this route declaration and export.
const routes = EFFRONT.Routes.make({ layout: RootLayout }).page("/", HomePage);

export default EFFRONT.make({ routes, layer: Greeting.layer });

ブラウザーで / を開くと Hello, Ada. と表示されます。 実装を差し替えるには、Page を変えずに、Greeting を提供する別の Layer を渡します。

サービスのスコープを選ぶ

同じ EFFRONT から作った Page、Layout、Component、Server Function は、アプリケーションサービスを利用できます。 複数のサービスを使う場合は、Application.effront<ServiceA | ServiceB>() のように union 型で宣言し、両方を提供する Layer を渡します。 組み合わせ方は Effect の Services と Layers を参照してください。

Effront はリクエストごとにアプリケーションの Layer を構築します。 スコープ内で確保したリソースは、Page が JSX を返した時点ではなく、レスポンス本文の読み取り完了、失敗、キャンセルまで利用できます。

サービス不足の型エラーを直す

エラーの箇所確認すること
Page の renderApplication.effront<Services>() でサービスを宣言するか、Middleware 付きの定義を使います。
EFFRONT.makeアプリケーションサービスを宣言した場合は layer を渡します。
渡した Layer宣言したサービスをすべて提供します。Layer.empty は Greeting を提供できません。

Middleware が提供するサービスの場合は、型エラーを消すためにアプリケーション全体の実装を追加せず、有効なスコープを確認してください。