{"id":23772,"date":"2019-12-01T08:00:00","date_gmt":"2019-11-30T23:00:00","guid":{"rendered":"https:\/\/www.techscore.com\/blog\/?p=23772"},"modified":"2019-12-06T20:31:53","modified_gmt":"2019-12-06T11:31:53","slug":"typescript_idl","status":"publish","type":"post","link":"https:\/\/www.techscore.com\/blog\/2019\/12\/01\/typescript_idl\/","title":{"rendered":"TypeScript\u3067React\u3068BFF\u306e\u9593\u306e\u901a\u4fe1\u306b\u30ab\u30bf\u3092\u3064\u3051\u308b"},"content":{"rendered":"<p>\u3053\u308c\u306f <a href=\"https:\/\/www.techscore.com\/blog\/2019\/11\/21\/techscore-advent-calendar-2019\/\">TECHSCORE Advent Calendar 2019<\/a> \u306e\uff11\u65e5\u76ee\u306e\u8a18\u4e8b\u3067\u3059\u3002<\/p>\n<h2>TL;DR<\/h2>\n<p>TypeScript \u3067 React \u3068 BFF \u306e\u9593\u306e\u901a\u4fe1\u306b\u578b\u3092\u3064\u3051\u3066\u307f\u305f\u3088\u3002<br \/>\n\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9\u306f TypeScript \u3067\u66f8\u3044\u3066\u308b\u306e\u3067\u3001\u5b9f\u88c5\u304c\u305d\u306e\u307e\u307e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u306a\u308b\u3088\u3002<br \/>\nReact \u5074\u3082 BFF \u5074\u3082\u304d\u3063\u3061\u308a\u578b\u304c\u3064\u304f\u306e\u3067\u958b\u767a\u6357\u308b\u3088\u3002<br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\">\u3053\u3053<\/a>\u306b\u5b9f\u88c5\u7f6e\u3044\u305f\u304b\u3089\u898b\u3066\u306d\u3002<\/p>\n<h2>\u306f\u3058\u3081\u306b<\/h2>\n<p>\u6700\u8fd1\u534a\u5e74\u307b\u3069 TypeScript \u3070\u3063\u304b\u308a\u66f8\u3044\u3066\u307e\u3059\u3002TypeScript \u3067 React App \u66f8\u3044\u3066\u3001TypeScript \u3067 BFF \u66f8\u3044\u3066\u3001\u300c\u55da\u547c\u3001\u578b\u304c\u3042\u308b\u3063\u3066\u5e78\u305b\u3060\u306a\u300d\u3063\u3066\u601d\u3063\u3066\u307e\u3057\u305f\u3002<br \/>\n\u3067\u3082\u552f\u4e00\u4e0d\u6e80\u304c\u3042\u308a\u307e\u3059\u3002React \u3068 BFF \u306e\u9593\u306e\u901a\u4fe1\u3002<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3092\u4f7f\u3063\u3066\u66f8\u3044\u3066\u308b\u3093\u3067\u3059\u304c\u3001<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3067 JSON \u53d6\u3063\u3066\u304f\u308b\u3068\u623b\u308a\u5024\u306f<span class=\"lang:ts decode:true  crayon-inline \" >any<\/span>\u306b\u306a\u3063\u3061\u3083\u3046\u3093\u3067\u3059\u3088\u306d\u3001\u5f53\u305f\u308a\u524d\u3067\u3059\u3051\u3069\u3002<\/p>\n<pre class=\"lang:ts decode:true \" >\nconst response = await fetch(url);\nconst json = await response.json();\n# json \u306e\u578b\u306f any !!\n<\/pre>\n<p>\u3053\u308c\u306a\u3093\u3068\u304b\u3057\u305f\u3044\u306a\u3001<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u4f7f\u3063\u305f\u901a\u4fe1\u3067\u3082\u3061\u3083\u3093\u3068\u578b\u3064\u3051\u305f\u3044\u306a\u3002<br \/>\n\u3053\u3046\u3044\u3046\u3068\u304d\u306f Swagger \u304b\u306a\u3001\u3067\u3082 Swagger \u9762\u5012\u3060\u306a\u3001\u6587\u6cd5\u899a\u3048\u3089\u3093\u306a\u3044\u3057\u3002<br \/>\n\u305d\u3082\u305d\u3082 React \u3082 BFF \u3082 TypeScript \u3067\u66f8\u3044\u3066\u308b\u306e\u306b\u3001\u308f\u3056\u308f\u3056\u5225\u306e\u6280\u8853\u6301\u3061\u8fbc\u3080\u306e\u3082\u5acc\u3060\u306a\u3002<\/p>\n<p>\u305d\u3046\u3044\u3046\u8a33\u3067\u8003\u3048\u3066\u307f\u307e\u3057\u305f\u3002<\/p>\n<h2>\u65b9\u91dd<\/h2>\n<ol>\n<li>React \u3068 BFF \u306e\u9593\u306e\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u306f TypeScript \u3067\u8a18\u8ff0\u3059\u308b\u3002\u3064\u307e\u308a IDL = TypeScritpt\u3002<\/li>\n<li>\u95a2\u6570\u547c\u3073\u51fa\u3057\u3063\u307d\u304f\u66f8\u3051\u308b\u3088\u3046\u306b\u3059\u308b\u3002<\/li>\n<li>\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306e\u5b9f\u88c5\u306f\u306a\u308b\u3079\u304f\u5171\u901a\u5316\u3059\u308b\u3002<\/li>\n<li>\u30b5\u30fc\u30d0\u30fc\u5074\u306e\u5b9f\u88c5\u306f\u306a\u308b\u3079\u304f\u5171\u901a\u5316\u3059\u308b\u3002<\/li>\n<\/ol>\n<p>\u6614\u61d0\u304b\u3057\u3044 CORBA \u306e IDL \u3068\u304b\u3001java.rmi \u306e\u30a4\u30e1\u30fc\u30b8\u3067\u3059\u3002<\/p>\n<p><a href=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/e60e2b04-cdcc-81b9-4fb0-3f5b37aca2c3.png\" rel=\"facebox\" rel=\"attachment wp-att-23867\"><img loading=\"lazy\" src=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/e60e2b04-cdcc-81b9-4fb0-3f5b37aca2c3.png\" alt=\"\" width=\"400\" height=\"299\" class=\"aligncenter size-full wp-image-23867\" srcset=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/e60e2b04-cdcc-81b9-4fb0-3f5b37aca2c3.png 400w, https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/e60e2b04-cdcc-81b9-4fb0-3f5b37aca2c3-300x224.png 300w\" sizes=\"(max-width: 400px) 100vw, 400px\" \/><\/a><br \/>\nStub \u3068 Skeleton\u3001Express App \u306f\u81ea\u52d5\u751f\u6210\u3059\u308b\u306e\u304c\u738b\u9053\u3067\u3059\u304c\u3001\u307e\u3041\u305d\u308c\u306f\u5225\u306e\u6a5f\u4f1a\u306b\u3002<br \/>\n\u4ee5\u4e0b\u3001\u56f3\u4e2d\u306e\u4e38\u6570\u5b57\u306e\u9806\u306b\u4f5c\u3063\u3066\u3044\u304d\u307e\u3059\u3002<\/p>\n<h2>\u2460 \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9<\/h2>\n<p>\u30e6\u30fc\u30b6\u30fc\u3092\u64cd\u4f5c\u3059\u308b\u30ea\u30e2\u30fc\u30c8\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u8003\u3048\u307e\u3059\u3002<br \/>\n\u3053\u306e\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u306f <span class=\"lang:ts decode:true  crayon-inline \" >create<\/span>\u3084<span class=\"lang:ts decode:true  crayon-inline \" >read<\/span>\u306a\u3069\u306e\u95a2\u6570\u3092\u6301\u3063\u3066\u3044\u3066\u3001\u305d\u308c\u305e\u308c\u306e\u5f15\u6570\u306b\u3069\u3093\u306a\u578b\u3092\u53d6\u308a\u3046\u308b\u304b\u3001\u623b\u308a\u5024\u304c\u3069\u3093\u306a\u578b\u306a\u306e\u304b\u3001\u3068\u3044\u3046\u3053\u3068\u3092\u7d20\u76f4\u306b TypeScript \u3067\u8a18\u8ff0\u3059\u308b\u3068\u3053\u3093\u306a\u611f\u3058\u306b\u306a\u308a\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.types\/UserBffType.ts\">\ntype UserBffType = {\n  create: (arg: {\n    name: string; \/\/      \u540d\u524d\n    age: number; \/\/       \u5e74\u9f62\n  }) => {\n    id: number; \/\/        ID\n    name: string; \/\/      \u540d\u524d\n    age: number; \/\/       \u5e74\u9f62\n    createdAt: string; \/\/ \u4f5c\u6210\u65e5\u6642\n    updatedAt: string; \/\/ \u66f4\u65b0\u65e5\u6642\n  };\n  read: ...(\u7565)...\n  update: ...(\u7565)...\n  delete: ...(\u7565)...\n};\n<\/pre>\n<p>\u5404\u95a2\u6570\u306f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u578b\u306e\u5f15\u6570\u3092\uff11\u3064\u3060\u3051\u53d6\u308b\u3088\u3046\u306b\u3057\u3066\u3044\u307e\u3059\u3002<br \/>\n\u30fb\u5f15\u6570\u3068\u3057\u3066\u8907\u6570\u306e\u5024\u3092\u6e21\u3057\u305f\u3044\u6642\u306f\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u3068\u3057\u3066\u6e21\u3057\u3066\u306d\u3002<br \/>\n\u30fb\u5f15\u6570\u306fJSON\u5316\u3055\u308c\u3066<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3067\u30ea\u30af\u30a8\u30b9\u30c8\u30dc\u30c7\u30a3\u3068\u3057\u3066\u9001\u4fe1\u3055\u308c\u308b\u3088\u3002<br \/>\n\u30fb<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u95a2\u6570\u306e\u623b\u308a\u5024\u3068\u3057\u3066\u8fd4\u3063\u3066\u304f\u308b\u3088\u3002<br \/>\n\u3068\u3044\u3046\u60f3\u5b9a\u3067\u3059\u3002<\/p>\n<h2>\u2461 Stub<\/h2>\n<p>Stub \u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u5074\u306e\u51e6\u7406\u3067\u3001\u5b9f\u969b\u306e\u901a\u4fe1\u3092\u62c5\u3046\u90e8\u5206\u3067\u3059\u3002<br \/>\n\u8981\u306f<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3092\u5b9f\u884c\u3057\u3066\u3001\u305d\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\uff08JSON\uff09\u306b\u578b\u3092\u3064\u3051\u305f\u308a\u3001\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u578b\u3067\u5236\u9650\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<p>\u3068\u3001\u305d\u306e\u524d\u306b\u3001\u3044\u304f\u3064\u304b\u4fbf\u5229\u306a\u5b9a\u7fa9\u3092\u3057\u3066\u304a\u304d\u307e\u3059\u3002<br \/>\n\u30ea\u30e2\u30fc\u30c8\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5185\u3067\u5b9a\u7fa9\u3059\u308b\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\uff08\u4e0a\u8a18\u306e<span class=\"lang:ts decode:true  crayon-inline \" >create<\/span>\u3084<span class=\"lang:ts decode:true  crayon-inline \" >read<\/span>\u306a\u3069\uff09\u306e\u578b\u3092<span class=\"lang:ts decode:true  crayon-inline \" >RemoteFunction<\/span>\u3068\u3057\u3001<span class=\"lang:ts decode:true  crayon-inline \" >RemoteParameter<\/span>\u3067\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\u306e\u5f15\u6570\u306e\u578b\u3092\u53d6\u5f97\u3067\u304d\u308b\u3088\u3046\u306b\u3057\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"types\/remoteTypes.ts\" >\n\/**\n * \u30ea\u30e2\u30fc\u30c8\u95a2\u6570\n *\n * const foo: RemoteFunction = (arg: { id: number }) => ({ name: '' });\n *\/\nexport type RemoteFunction = (arg: any) => any;\n\n\/**\n * RemoteFunction \u306e\u5f15\u6570\u306e\u578b\u3092\u53d6\u5f97\u3059\u308b\n *\n * type Foo = (arg: { id: number }) => { name: string };\n * type Arg = RemoteParameter<Foo>;\n * \/\/ type Arg = { id: number };\n *\/\nexport type RemoteParameter<T extends RemoteFunction> = T extends (\n  arg: infer P\n) => any\n  ? P\n  : never;\n<\/pre>\n<p>\u3055\u3066\u3001Stub\uff08\uff1d\u5b9f\u969b\u306b<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3059\u308b\u3068\u3053\u308d\uff09\u3092\u4f5c\u308a\u307e\u3059\u3002<\/p>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >post<\/span>\u306f\u300c\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\u3068 URL \u3092\u6307\u5b9a\u3059\u308b\u3068\u3001<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3057\u3066\u304f\u308c\u308b\u975e\u540c\u671f\u95a2\u6570\u3092\u8fd4\u3059\u300d\u95a2\u6570\u3067\u3059\u3002<br \/>\nClient \u3067\u300c<span class=\"lang:ts decode:true  crayon-inline \" >fetch<\/span>\u3057\u3066\u304f\u308c\u308b\u975e\u540c\u671f\u95a2\u6570\u300d\u3092\u547c\u3073\u51fa\u3059\u3068\u3044\u3046\u60f3\u5b9a\u3067\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.stubs\/post.ts\" >\nexport const post = <T extends RemoteFunction>(input: RequestInfo) => async (\n  arg: RemoteParameter<T>\n): Promise<ReturnType<T>> => {\n  const response = await fetch(input, {\n    method: 'POST',\n    headers: { 'Content-Type': 'application\/json' },\n    body: JSON.stringify(arg),\n  });\n  if (!response.ok) {\n    const message = `${response.status} (${response.statusText})`;\n    throw new Error(message);\n  }\n  const json = await response.json();\n  return json;\n};\n<\/pre>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >post<\/span>\u95a2\u6570\u306f\u4ee5\u4e0b\u306e\u3088\u3046\u306b\u4f7f\u3044\u307e\u3059\u3002<br \/>\n\u3053\u308c\u306b\u3088\u3063\u3066 URL \u3068\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\u306e\u578b\u3092\u7d50\u3073\u3064\u3051\u3066\u3044\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.stubs\/UserBff.ts\" >\nconst create = post<UserBffType['create']>('\/user\/create');\nconst read = post<UserBffType['read']>('\/user\/read');\n...(\u7565)...\n<\/pre>\n<p>VS Code \u3067\u898b\u308b\u3068\u3001<span class=\"lang:ts decode:true  crayon-inline \" >create<\/span>\u306e\u5f15\u6570\u3068\u623b\u308a\u5024\u306b\u3061\u3083\u3093\u3068\u578b\u304c\u3064\u3044\u3066\u3044\u308b\u3053\u3068\u304c\u308f\u304b\u308a\u307e\u3059\u3002<br \/>\n<a href=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/fea6c044-8bd1-9dff-1af9-01a23810862c.png\" rel=\"facebox\" rel=\"attachment wp-att-23787\"><img loading=\"lazy\" src=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/fea6c044-8bd1-9dff-1af9-01a23810862c.png\" alt=\"\" width=\"421\" height=\"244\" class=\"aligncenter size-full wp-image-23787\" srcset=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/fea6c044-8bd1-9dff-1af9-01a23810862c.png 421w, https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/fea6c044-8bd1-9dff-1af9-01a23810862c-300x174.png 300w\" sizes=\"(max-width: 421px) 100vw, 421px\" \/><\/a><\/p>\n<p>\u30b8\u30a7\u30cd\u30ea\u30af\u30b9\u3067\u578b\u3092\u6307\u5b9a\u3057\u306a\u3044\u3068<span class=\"lang:ts decode:true  crayon-inline \" >any<\/span>\u306b\u306a\u3063\u3066\u3057\u307e\u3044\u307e\u3059\u3002\u3053\u308c\u306f\u5b09\u3057\u304f\u306a\u3044\u3002<br \/>\n<a href=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/edb76fb3-11c2-3da5-2a4c-aa7115761c0f.png\" rel=\"facebox\" rel=\"attachment wp-att-23788\"><img loading=\"lazy\" src=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/edb76fb3-11c2-3da5-2a4c-aa7115761c0f.png\" alt=\"\" width=\"349\" height=\"54\" class=\"aligncenter size-full wp-image-23788\" srcset=\"https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/edb76fb3-11c2-3da5-2a4c-aa7115761c0f.png 349w, https:\/\/www.techscore.com\/blog\/wp\/wp-content\/uploads\/2019\/11\/edb76fb3-11c2-3da5-2a4c-aa7115761c0f-300x46.png 300w\" sizes=\"(max-width: 349px) 100vw, 349px\" \/><\/a><\/p>\n<p>\u3055\u3089\u306b\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\u3092\u3072\u3068\u307e\u3068\u3081\u306b\u3057\u3066\u304a\u304d\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.stubs\/UserBff.ts\" >\nexport const UserBff: AsyncRemote<UserBffType> = {\n  create,\n  read,\n  ...(\u7565)...\n};\n<\/pre>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >AsyncRemote<\/span>\u306e\u5b9a\u7fa9\u306f\u3053\u3093\u306a\u611f\u3058\u3002\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9\u306e\u5404\u95a2\u6570\u3092\u975e\u540c\u671f\u306b\u3057\u305f\u3082\u306e\u3001\u3092\u4f5c\u6210\u3059\u308b\u306e\u306b\u4f7f\u3044\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"types\/remoteTypes.ts\" >\n\/**\n * RemoteFunction \u3092\u975e\u540c\u671f\u306b\u3059\u308b\n *\n * type Foo = (arg: { id: number }) => { name: string };\n * type Bar = AsyncRemoteFunction<Foo>;\n * \/\/ type Bar = (arg: {id:number}) => Promise<{name: string}>\n *\/\ntype AsyncRemoteFunction<T extends RemoteFunction> = (\n  arg: RemoteParameter<T>\n) => Promise<ReturnType<T>>;\n\n\/**\n * Remote \u306e\u5404\u30e1\u30f3\u30d0\u3092\u975e\u540c\u671f\u306b\u3059\u308b\n *\n * type Foo = { foo: (arg: { id: number }) => { name: string } };\n * type Bar = AsyncRemote<Foo>;\n * type Bar = { foo: (arg: { id: number }) => Promise<{ name: string }> };\n *\/\nexport type AsyncRemote<T extends { [P in keyof T]: RemoteFunction }> = {\n  [P in keyof T]: AsyncRemoteFunction<T[P]>;\n};\n<\/pre>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >AsyncRemote<\/span>\u3092\u4f7f\u3046\u3053\u3068\u3067\u3001<span class=\"lang:ts decode:true  crayon-inline \" >UserBff<\/span>\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306b\u904e\u4e0d\u8db3\u304c\u3042\u308b\u5834\u5408\u306b\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc\u306b\u306a\u3063\u3066\u304f\u308c\u307e\u3059\u3002\u3068\u3066\u3082\u5b09\u3057\u3044\u3002<\/p>\n<h2>\u2462 Client<\/h2>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >UserBff.create<\/span>\u306f\u901a\u5e38\u306e\u95a2\u6570\u547c\u3073\u51fa\u3057\u306e\u3088\u3046\u306b\u4f7f\u3044\u307e\u3059\u3002 \u3068\u3066\u3082\u7c21\u5358\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"App.tsx\" >\nconst cerateRes = await UserBff.create({ name: 'Alice', age: 20 });\nconsole.log('create', cerateRes);\n<\/pre>\n<h2>\u2463 ServerImpl\uff08\u30b5\u30fc\u30d0\u30fc\u5b9f\u88c5\uff09<\/h2>\n<p>\u6b21\u306b\u30b5\u30fc\u30d0\u30fc\u5074\u3067\u30ea\u30e2\u30fc\u30c8\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u5b9f\u88c5\u3057\u307e\u3059\u3002<br \/>\n<span class=\"lang:ts decode:true  crayon-inline \" >UserBffType['create']<\/span>\u306b\u3088\u3063\u3066\u3001\u5f15\u6570\u3068\u623b\u308a\u5024\u306e\u578b\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059\u3002\u3053\u306e\u304a\u304b\u3052\u3067\u3001\u5f15\u6570\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u3092\u9593\u9055\u3048\u305f\u308a\u3001\u623b\u308a\u5024\u306e\u30d7\u30ed\u30d1\u30c6\u30a3\u306b\u4e0d\u8db3\u304c\u3042\u3063\u305f\u308a\u3057\u305f\u5834\u5408\u306b\u306f\u3001\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc\u306b\u306a\u308a\u307e\u3059\u3002\u3053\u308c\u3082\u5b09\u3057\u3044\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.impls\/UserBff.ts\" >\nconst create: UserBffType['create'] = arg => {\n  \/\/ \u4e2d\u8eab\u306e\u51e6\u7406\u306f\u9069\u5f53\n  console.log('create', arg);\n  const { name, age } = arg;\n  const id = 1;\n  const now = new Date();\n  const createdAt = `${now}`;\n  const updatedAt = createdAt;\n  return { id, name, age, createdAt, updatedAt };\n};\n...(\u7565)...\n<\/pre>\n<h2>\u2464 Skeleton<\/h2>\n<p>\u30b5\u30fc\u30d0\u30fc\u5074\u3067\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u53d7\u3051\u53d6\u3063\u3066\u3001\u30b5\u30fc\u30d0\u30fc\u5b9f\u88c5\u3092\u547c\u3073\u51fa\u3059\u7b87\u6240\u3092\u4f5c\u308a\u307e\u3059\u3002<br \/>\n\u30d5\u30ec\u30fc\u30e0\u30ef\u30fc\u30af\u306b\u3088\u3063\u3066\u5b9f\u88c5\u65b9\u6cd5\u304c\u9055\u3044\u307e\u3059\u304c\u3001\u4ee5\u4e0b\u306f Express \u306e\u4f8b\u3067\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"bff.skeletons\/requestHandler.ts\">\nexport const requestHandler = <T extends RemoteFunction>(\n  func: (arg: RemoteParameter<T>) => ReturnType<T>\n) => (\n  req: express.Request,\n  res: express.Response,\n  next?: express.NextFunction\n) => {\n  const { body } = req;\n  try {\n    const response = func(body);\n    res.json(response);\n  } catch (err) {\n    if (next) {\n      next(err);\n    }\n  }\n};\n<\/pre>\n<p>\u300cServerImpl \u3067\u5b9f\u88c5\u3057\u305f\u95a2\u6570\u3092 Express \u306e\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u306b\u5909\u63db\u3059\u308b\u95a2\u6570\u300d\u3092\u4f5c\u3063\u3066\u3044\u307e\u3059\u3002<br \/>\n\u30eb\u30fc\u30c6\u30a3\u30f3\u30b0\u30b3\u30fc\u30eb\u30d0\u30c3\u30af\u5185\u3067\u306f\u3001Express \u306e\u30ea\u30af\u30a8\u30b9\u30c8\u304b\u3089\u30dc\u30c7\u30a3\u3092\u53d6\u308a\u51fa\u3057\u3066<span class=\"lang:ts decode:true  crayon-inline \" >func<\/span>\u306b\u6e21\u3057\u3001\u623b\u308a\u5024\u3092\u30ec\u30b9\u30dd\u30f3\u30b9\u3068\u3057\u3066\u8fd4\u3057\u307e\u3059\u3002<\/p>\n<h2>\u2465 Express App<\/h2>\n<p><span class=\"lang:ts decode:true  crayon-inline \" >requestHandler<\/span>\u306f\u3053\u3093\u306a\u98a8\u306b\u4f7f\u3044\u307e\u3059\u3002<br \/>\n\u3053\u308c\u306b\u3088\u3063\u3066 URL \u3068\u30ea\u30e2\u30fc\u30c8\u95a2\u6570\u306e\u5b9f\u88c5\u3092\u7d50\u3073\u3064\u3051\u3066\u3044\u307e\u3059\u3002<\/p>\n<pre class=\"toolbar:1 lang:ts decode:true \" title=\"app.ts\">\nimport express from 'express';\n\nconst app = express();\n...(\u7565)...\n\napp.post('\/user\/create', requestHandler(UserBff.create));\napp.post('\/user\/read', requestHandler(UserBff.read));\n...(\u7565)...\n<\/pre>\n<p>\u3000<br \/>\n\u4ee5\u4e0a\u3001\u3059\u3079\u3066\u306e\u5b9f\u88c5\u306f<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\">\u3053\u3061\u3089<\/a>\u306b\u7f6e\u3044\u3066\u307e\u3059\u3002<\/p>\n<p>\u7ae0\u3054\u3068\u306e\u5b9f\u88c5\u306f\u3053\u3061\u3089\u2193<br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/ui\/src\/bff.types\/UserBffType.ts\">\u2460 \u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9<\/a><br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/tree\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/ui\/src\/bff.stubs\">\u2461 Stub<\/a><br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/ui\/src\/App.tsx#L9-L40\">\u2462 Client<\/a><br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/bff\/src\/bff.impls\/UserBff.ts\">\u2463 ServerImpl\uff08\u30b5\u30fc\u30d0\u30fc\u5b9f\u88c5\uff09<\/a><br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/bff\/src\/bff.skeletons\/requestHandler.ts\">\u2464 Skeleton<\/a><br \/>\n<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/bff\/src\/app.ts#L21-L26\">\u2465 Express App<\/a><\/p>\n<p>\u8a18\u4e8b\u4e2d\u3067\u89e6\u308c\u306a\u304b\u3063\u305f\u300c<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/bff\/src\/app.ts#L25\">\u30b5\u30fc\u30d0\u30fc\u5074\u306b\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u304c\u306a\u304b\u3063\u305f\u5834\u5408<\/a>\u306f\u3069\u3046\u306a\u308b\u306e\uff1f\u300d\u3068\u304b\u300c<a href=\"https:\/\/github.com\/higashi-masaru\/typescript-idl-sample\/blob\/e5bb76d548458974d21b6a2370cf1bb1621d2d84\/bff\/src\/bff.impls\/UserBff.ts#L48\">\u30b5\u30fc\u30d0\u30fc\u5074\u3067\u4f8b\u5916\u304c\u767a\u751f\u3057\u305f\u5834\u5408<\/a>\u306f\u3069\u3046\u306a\u308b\u306e\uff1f\u300d\u306b\u95a2\u3057\u3066\u3082\u5b9f\u88c5\u3057\u3066\u3044\u307e\u3059\u3002<\/p>\n<h2>\u3055\u3044\u3054\u306b<\/h2>\n<p>TypeScript \u3067 React \u3068 BFF \u306e\u9593\u306e\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u3092\u5b9a\u7fa9\u3057\u3066\u307f\u307e\u3057\u305f\u3002<br \/>\n\u30b8\u30a7\u30cd\u30ea\u30af\u30b9\u3067\u3054\u306b\u3087\u3054\u306b\u3087\u3059\u308b\u3053\u3068\u3067\u3001\u30e6\u30fc\u30b6\u30fc\u304c\u30af\u30e9\u30a4\u30f3\u30c8\u5074\u3067\u547c\u3073\u51fa\u3059\u95a2\u6570\u3068\u3001\u30b5\u30fc\u30d0\u30fc\u5074\u3067\u5b9f\u88c5\u3059\u308b\u95a2\u6570\u306b\u578b\u3092\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3057\u305f\u3002<br \/>\n\u30a4\u30f3\u30bf\u30fc\u30d5\u30a7\u30fc\u30b9\u5b9a\u7fa9\u304c\u305d\u306e\u307e\u307e\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306b\u306a\u308b\u3057\u3001\u578b\u306e\u4e0d\u4e00\u81f4\u306f\u30b3\u30f3\u30d1\u30a4\u30eb\u30a8\u30e9\u30fc\u306b\u306a\u308b\u3057\u3067\u3001\u3044\u3044\u3053\u3068\u3065\u304f\u3081\u3067\u3059\u3002<br \/>\n\u6700\u521d\u306b\u300cStub \u3068 Skeleton\u3001Express App \u306f\u81ea\u52d5\u751f\u6210\u3059\u308b\u306e\u304c\u738b\u9053\u300d\u3068\u66f8\u304d\u307e\u3057\u305f\u304c\u3001\u3053\u306e\u304f\u3089\u3044\u306e\u91cf\u306a\u3089\u624b\u3067\u66f8\u3044\u3066\u3082\u5927\u4e08\u592b\u304b\u306a\u3001\u578b\u304c\u306a\u3044\u3088\u308a\u3042\u308b\u65b9\u304c\u3044\u3044\u3057\u306d\u3002<\/p>\n<p>\u306a\u304a\u3001\u4eca\u56de\u306f React \u3068 BFF \u306e\u9593\u306e\u901a\u4fe1\u306b\u7279\u5316\u3057\u305f\u5185\u5bb9\u3067\u3057\u305f\u304c\u3001\u540c\u3058\u624b\u6cd5\u3067\u65e2\u5b58\u306e Web API \u3092\u547c\u3073\u51fa\u3059\u5834\u5408\uff08\u3064\u307e\u308a BFF \u3068 API \u306e\u9593\u306e\u901a\u4fe1\uff09\u306b TypeScript \u3067\u578b\u3092\u3064\u3051\u308b\u3053\u3068\u3082\u3067\u304d\u307e\u3059\u3002\u3053\u308c\u306b\u3064\u3044\u3066\u306f\u307e\u305f\u306e\u6a5f\u4f1a\u306b\u3067\u3082\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u3053\u308c\u306f TECHSCORE Advent Calendar 2019 \u306e\uff11\u65e5\u76ee\u306e\u8a18\u4e8b\u3067\u3059\u3002<\/p>\n<p>TL;DR<\/p>\n<p>TypeScript \u3067 React \u3068 BFF \u306e\u9593\u306e\u901a\u4fe1\u306b\u578b\u3092\u3064\u3051\u3066\u307f\u305f\u3088\u3002<br \/><a href=\"https:\/\/www.techscore.com\/blog\/2019\/12\/01\/typescript_idl\/\">\u7d9a\u304d\u3092\u8aad\u3080...<\/a><\/p>\n","protected":false},"author":44,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[332,18],"tags":[141,334,335,275,333],"_links":{"self":[{"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/posts\/23772"}],"collection":[{"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/users\/44"}],"replies":[{"embeddable":true,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/comments?post=23772"}],"version-history":[{"count":81,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/posts\/23772\/revisions"}],"predecessor-version":[{"id":24446,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/posts\/23772\/revisions\/24446"}],"wp:attachment":[{"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/media?parent=23772"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/categories?post=23772"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.techscore.com\/blog\/wp-json\/wp\/v2\/tags?post=23772"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}