iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0

這篇要來介紹的是 Effect 內建的資料格式的驗證工具 Schema ,另外我之前也提到,我個人平常還是偏好使用 zod 這個老牌的格式驗證為主,這篇我們一起來看 Schema 要如何使用,與何時使用

如何使用 Effect Schema

我們可以像這樣定義一個 Schema

import { Schema } from 'effect'

const DataSchema = Schema.Struct({
  foo: Schema.String,
  bar: Schema.Number,
});

這樣看其實跟 zod 好像沒有什麼差別,只不過一些 API 不太一樣,例如 z.object 變成了 Schema.Struct

如果你要 parse 資料,你會需要使用到 Schema.decodeUnknown

const parseData = Schema.decodeUnknown(DataSchema);

接著你可以用它來 parse 你的資料

pipe(
  parseData({ foo: "string", bar: 42 }),
  Effect.tap(Console.log),
  Effect.runPromise
);

pipe(
  parseData({ baz: 1 }),
  // 因為上面的資料會產生錯誤,這邊用 `Effect.fipt` 把 Error 變成結果好讓我們可以 log 出來
  Effect.flip,
  Effect.tap((x) => Console.log(x.message)),
  Effect.runPromise
);

(playground link)

上面的會輸出

{ foo: 'string', bar: 42 }
{ readonly foo: string; readonly bar: number }
└─ ["foo"]
   └─ is missing

第一個是成功 parse 的資料,第二個則是 error message ,你可以看到 Effect 預設的 error message 很容易理解

不過你到這邊可能會想,為什麼 Effect 裡的 parse 是叫 decode

Effect Schema 的 encode 與 decode

Effect 裡的 Schema 是可以做雙向的轉換的,這樣講可能有點抽像,我們實際看一個例子,我們把上面的 DataSchema 再用 Schema.parseJson 包起來,這可以讓我們的 schema 可以先做 JSON.parse 再來 parse 資料

const JsonDataSchema = Schema.parseJson(DataSchema);
const parseJsonData = Schema.decodeUnknown(JsonDataSchema);

接下來我們讓它實際 parse 一個經過 JSON.stringify 的資料看看

pipe(
  parseJsonData(JSON.stringify({ foo: "string", bar: 42 })),
  Effect.tap(Console.log),
  Effect.runPromise
);

(playground link)

你會看到它正常的 parse 出結果

{ foo: 'string', bar: 42 }

像這樣 JSON.parseJSON.stringify 是一對相反的處理,如果我們要把這個資料再轉回去 json 是不是就要做 JSON.stringify ,但我們也可以用 Schema.encode ,我們先建立一個 encodeJsonData

const encodeJsonData = Schema.encode(JsonDataSchema);

然後我們把資料做 parse 再 encode 回去看看

pipe(
  parseJsonData(JSON.stringify({ foo: "string", bar: 42 })),
  Effect.flatMap((data) => encodeJsonData(data)),
  Effect.tap(Console.log),
  Effect.runPromise
);

(playground link)

你會看到它又變回了 json

{"foo":"string","bar":42}

在 Effect 的 Schema 中,資料就是可以像這樣雙向的轉換

https://ithelp.ithome.com.tw/upload/images/20251011/20111802xta6eSj4EP.png

Effect 的 Schema 應該是我第一個看過有這樣的概念的 schema 驗證的工具,正好 zod 在 4.1 版也新增了類型的功能叫 codec

codec 可以做到說讓我們定義輸入跟輸出的型態,同時定義怎麼做轉換,例如要做到一樣的效果,我們要用 jsonCodec

import * as z from 'zod';

const ZodDataSchema = jsonCodec(
  z.object({
    foo: z.string(),
    bar: z.number(),
  })
);

題外話, zod 如果用 namespace import 大小會小很多,你可以自己到 https://bundlejs.com 測試看看

zod vs Effect Schema

先說結論,大多數的時候,我自己都還是用 zod ,原因其實是因為 zod 的生態系 ,雖然現在大部份會使用到 schema 的套件都開始支援 standard schema ,但 standard schema 只有定義怎麼做 parse ,如果要一些進階的功能就還是需要跟 schema 的套件做較深度的整合,加上 Effect Schema 需要額外的轉換來變成 standard schema ,這使得 Effect Schema 使用起來較不方便

Schema.standardSchemaV1(DataSchema)

但什麼時候用 Effect 的 schema 呢?當你在 Effect 裡處理資料的時候,這時候 Effect Schema 使用起來就方便的很多

這篇我們介紹了 Effect 的資料驗證的 Schema ,也介紹了雙向的資料轉換的概念,下一篇要來講的是模式比對

Reference


上一篇
25. Effect 與 Observability
下一篇
27. Match: tag 與模式比對
系列文
Effect 魔法:打造堅不可摧的應用程式28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言