概要
Vueで開発中のアプリにTypeScriptを導入し、サーバー側とのやり取りをJSONではなく、Protocol Buffersにしたところ、
サーバー側APIのインタフェース変更に強くなり、開発が柔軟になった。
登場人物の紹介
Vue
モダンなJavaScriptフレームワーク。もともとAngular4とかは触ったことが合ったが、それに比べて規約がゆるく柔軟に書きやすい感じはあった。
ただAngularのTypeScriptで書く感じに慣れていると、型がないことによる実行時のエラーが何かモヤっとする。
TypeScript
AltJS。JavaScriptに型がつけられる、しょうもないミスを減らせて嬉しい。油断するとすぐanyにしてしまう。
Protocol Buffers
.protoというファイルでインタフェースを定義し、言語に合わせてトランスパイルすることで、
フロントエンド/バックエンドのインタフェースを一つのファイルで定義することができる。
定義内容
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
}
フロント<->サーバーのデータやり取りで一番多いフォーマットはJSONだと思ってますが、
JSONの難点として、サーバー側のインタフェースの変更があったときに気づきにくいというのがあります。
解決手段として、SwaggerによってAPIを定義していくというのもありますが、アプリ開発時にProtocol Buffersを利用したところ非常に便利だったので、
Webでもやりたいなーということで探したところ、protobuf.jsというのが存在したので利用してみることに。
Protocol Buffersの組み込み方
- サーバー<->アプリのAPIのインタフェースとして.protoファイルを定義する
message User {
int32 id = 1;
string name = 2;
}
- サーバー用(今回はPHPでした)とフロント用のインタフェースを生成
pbjs -t static-module -w commonjs -o compiled.js user.proto
- TypeScriptから型定義を扱えるようにするため、.d.tsファイルを生成
pbts -o compiled.d.ts compiled.js
あとは生成されたjsと.d.tsを組み込むだけ。
axiosを利用した利用方法
VueのHttpClientと言えばaxiosという感じなのでAxiosからの利用方法。
Protocol Buffersは通信自体はバイナリで行われるので、axiosでResponseを受け取ったあとにdecodeしてやる必要があります。
axios.get('/user',{
transformResponse:[function(data: any){
return User.decode(data) // バイナリであるdataをUser型にdecodeしている
}]
}).then(user =>{
console.log(user.name)
})
これでUserデータが型のついた状態で扱えるようになります。
サーバー側も同様のprotoファイルから生成された型を通信で利用している限り、繋いだときのインタフェースのミスは起きにくくなります。
protoファイル上でプロパティ名が変更になった際も、.protoファイルを再度transpileすることで、
プロパティが変わった場所はコンパイルエラーになるため、実行時エラーも未然に防ぐことができます。
Vueで更に便利に利用するためには
VueとTypeScriptは実はあまり相性が良くありません。
というのも、コンパイルエラーはVueのtemplateの中まで見てくれないため、protoで生成された型を直接template内部で利用していた場合は、その部分が実行時まで分からなくなってしまうんですね。
<template>
<div>
{{user.id}} // ここでプロパティ名を間違えていてもTypeScriptのコンパイラが検知してくれない
</div>
</template>
解決策として、Vue側でテンプレートを利用せず、描画関数を利用したtsx記法で書くことができます。
tsxは基本TypeScriptの糖衣構文なので、コンパイルエラーで検知することができます。
@Component
export default class UserComponent extends Vue {
render() {
return(<div>{user.id}</div>) // TypeScriptの世界なのでコンパイルが検知する
}
}
まとめ
- TypeScript + ProtocolBuffersを導入することで、サーバー側のAPI変更の取り込みが容易になる。
- Vue + TypeScriptの場合はTSX記法を利用することで、より型の特性を強力に支えて便利
そんな感じです。