一種API代碼結構的設計思路

Twitter's API Playground
Twitter's API Playgroundhtml

Prologue

在寫API的過程當中有這樣三種產物git

  • 文檔程序員

    幾乎沒人愛寫文檔,寫了也懶得維護。但是同時API的文檔對於其餘程序員來講又是賴以生存的必需品。所以你們對文檔都是愛恨交加,恨本身要維護文檔,愛別人寫好的漂亮文檔;恨別人的爛文檔錯文檔,愛本身隨便亂寫乃至不寫文檔。github

  • 操場web

    比文檔更高一個層次的奢侈品,不用寫代碼簡單點點或者repl形式立刻就能探索接口的行爲。不像僅對別人,操場的存在對本身開發接口也是頗有幫助的。json

    沒操場的時候,你們每每人肉建一個文件當操場用,在裏面各類玩API,但使着編譯型語言的兄弟們沒那麼好運,他們更須要有操場。segmentfault

    固然若是實踐TDD或BDD的話,用例大概能代替操場一部分的做用,但這隻對寫接口的人管用。對調用接口的人來講,操場的做用是難以取代的。api

  • 字段校驗邏輯數據結構

    本身寫接口的時候必需要作的事情。沒作那是100%bug。dom

想一想這三個產物的共同特色是什麼?插入一段廣告,哦不,我先把他們捏成一張表

別人的接口 本身的接口
文檔 沒有會死 沒用,不想寫
操場 超級提高幸福感 想用,懶得寫
字段校驗 不太關心 必須寫

他們的共同特色是均源自接口輸入的schema

你們爲啥不喜歡寫文檔?爲啥懶得實現操場?我以爲極可能源自程序員的直覺。程序員天生討厭重複,他們知道重複意味着修改的時候要同步維護,意味着大量重複的勞動和不一樣步帶來的各類巨坑,Duplicate Is EvilDUPLICATE IS EVIL

換個角度說,怎麼誘使程序員乖乖地寫文檔呢?首先利誘「寫文檔的話送你個操場玩玩」,而後威逼「反正你也得校驗字段,我們校驗字段的方式就是寫文檔」,最後再給個棗子「這文檔不用維護,之後改程序的同時文檔自動一塊兒改」

前言到此爲止,結論只有一個:

咱們要讓文檔、操場、字段校驗三位一體!讓不寫文檔比寫文檔難!讓全部接口都有100%準確的文檔和操場!消滅天下沒文檔的接口!消滅一切和實際接口不符的文檔!

具體實現的思路其實剛纔已經偷偷提到了,那就是聚焦接口的輸入schema,以schema做爲數據源,文檔、操場、字段校驗是schema的3種不一樣的應用。因此咱們要構建的就是 a)meta-schema,即如何定義schema b)如何經過schema生成3種不一樣的產物。

Meta-Schema

程序員作事大致上有兩種選擇:找現成的輪子削成方的來用或本身造個方的輪子。咱們想要的輪子「方」在哪裏呢?嗯,schema你們都拿來作校驗,但咱們但願不只能校驗,還能生成文檔和操場,也就是說但願它可以內嵌一些描述文字,最好校驗規則也能輕鬆轉換成文字展現。

本身造輪子的話,下面是一個基本的結構能夠參考

class Schema {
    string uri;//接口位置/調用時的名稱/url等
    string name;//接口中文名
    string desc;//說明
    array fields;//接口字段
}

class Field {
    string key;//字段key
    string desc;//說明
    bool required;//是否必填
    array constraints;//字段約束
}

class Constraint {
    bool check(value);//校驗
    string describe();//描述
}

//Constraint常見的子類有:類型校驗,長度/範圍校驗,正則校驗等

找輪子的話,我用過json-schema作這一塊,能用,不少語言都有校驗的實現,還有相似json-editor這樣的web editor實現,操場比較好搞。大致上能內嵌說明文字,各類語言都有良好實現,數據結構清晰容易導入導出的schema項目均可以用。

DSL for Meta-Schema

「好麻煩,我仍是if if if吧」

只有schema還不夠,你會須要負責教會全部同事一門新手藝,這可能將咱們的努力毀於一旦,本身用起來也不爽。咱們要的是DSL,要IDE的代碼提示,要code-as-configuration。

怎麼實現DSL超出本文範圍,有機會我會再寫這方面的東西,js的話大概300行代碼就能實現相似這樣的dsl了

jslegate().define
        .name('測試接口')
        .desc('演示API用的測試接口')
        .cmd('test')
        .param
            .int('num', '一個數字', [3, 100])
            .string('str', '字符串', [2, 5])
            .regex('reg', '有追求的字符串', /a.+b/)
        .endParam
        .logic(function(param) {
            return {
                result: 'from remote',
                param: param
            };
        })
    .endDefine
    .mount(legateServer);

有了DSL,基本上已經能夠宣告不寫文檔比寫文檔難了,下面要給按咱們的meta-schema作事的乖孩子說好的三大產物。

顯靈

其實本來寫到這裏就能夠收筆了,由於定義好了數據結構,寫寫視圖對程序員來講實在沒啥挑戰,不是麼?

文檔就是

loop schemas schema
  show schema
  loop schema.fields field
    show field

操場就是文檔套上

html<form target="result">
</form>
<iframe id="result">

校驗就是

loop schema.fields field
  if no $data[field]
    if field.required
      BIG-BANG!
    else
      continue

  loop field.constraints constraint
    constraint.check $data[field]

啊,不當心還順便實現了分發或者說路由呢

loop schemas schema
  if $request match schema.uri
    return run schema, $request

NOT-FOUND!

是否是根本停不下來?

另外一個好消息是,這個思路下各類其餘開源項目都很容易拿過來套上,好比以前提過的json-schemajson-editor,好比最近的swagger.io等等,只要把握住核心是schema,操場/文檔/校驗邏輯等都是schema的視圖,世界便盡在咱們的掌握之中。

附《The Pragmatic Programmer》中的相關tips

[11] Don't Repeat Yourself
[12] Make It Easy to Reuse
[17] Program Close to the Problem domain
[68] Build Documentation In, Don't Bolt It On


轉載自 http://press.mcfog.wang/2015/02/my-api-programming-style/
前情回顧 如何編寫API的文檔?

相關文章
相關標籤/搜索