自動生成Android,iOS的REST API訪問代碼

jopen 9年前發布 | 35K 次閱讀 REST WEB服務/RPC/SOA

上個月,介紹了生成Java JDBC訪問代碼,從SQL文件,后面應用到我負責的幾個實際的項目,效果不錯, 程序清晰了很多,也更好維護。

用類似的思路,我做了一個新的工具: api-kit,移動開發從中受益。

移動開發:Android,iOS,RESTful API

移動開發,下面幾個環節免不了:

  1. 負責Server端開發的同學,寫API,寫文檔
  2. 負責Android的同學,根據文檔,以及和server端同學的交流,實現和服務器的通信代碼
  3. 負責iOS的同學,根據文檔,以及和server端同學的交流,實現和服務器的通信代碼

這里面有一些重復: 負責server的同學開發API后,寫文檔是把同樣的信息,表達了兩次,一次是在code里面,一次在文檔。 客戶端同學實現各自平臺的訪問代碼,是重復,因為這部分信息是server端的code(或者文檔)的一次翻譯(跨語言,跨平臺)。

  1. 信息在這個過程中是無創造的復制(或者翻譯,即沒有引入更多的信息)
  2. 不能保證復制的正確性,比如文檔錯誤,客戶端寫code引入bug,等
  3. 復制的成本較高:溝通成本,寫code的成本
  4. 如果API重構,這個改動,需要在其它幾個地方replay

這幾天,我寫了一個程序,api-kit,通過自動生成代碼的方式,解決這里面的大部分重復,使信息的流動更高效和快捷。

例子

假設API描述是這樣的:

// 這是api-kit的輸入,輸出是各個平臺的code:Android, iOS, Server端
struct Book {
    i32 id
    string title
    string isbn
    float32 price
    string description
}

@url(/books/newest)
@get
func list<Book> getNewest(i32 limit, i32 offset);

@url(/books/search)
@get
func list<Book> searchBook(string q, i32 limit, i32 offset);

API描述是api-kit的輸入,輸出是各個平臺(Server,Android, iOS)的code。

生成的Server端code

  1. IHandler interface
  2. Book類
  3. hook這個interface到servlet的支持代碼(參數解析,綁定,dispatch)
public interface IHandler {
    // Called before every function. Use cases: setup context, authentication return false to abort further execution.
    public boolean before(Context context);

    // Called after every function. One use case is logging
    public void after(Context context);


    // GET /api/books/newest
    public List<Book> GetNewest(Context context, int limit, int offset);

    // GET /api/books/search
    public List<Book> SearchBook(Context context, String q, int limit, int offset);
}

服務器端的工作簡化為實現這個Interface

生成的Android端code

生成的code,處理url拼接,返回值解析,暴露給程序員的是函數:

自動生成Android,iOS的REST API訪問代碼

零依賴,能有效的減少apk的體積。在compiler的幫助下,做到類型安全,服務器重構后,這邊會編譯出錯,refactor會方便一些。

生成的iOS的code

iOS顯然是需要支持的。先花了一天時間,學習swift,并完成swift的code生成。在和公司的iOS工程師溝通時,他們在用objective-c, 于是又多花了一天時間看oc,并生成oc的code,語法有點不太習慣,但還是搞定了。

自動生成Android,iOS的REST API訪問代碼

也是零依賴的,能有效的減少app的體積。由于oc支持類型安全的dict和arr挺困難,于是,通過注釋幫助一點。

自動生成Android,iOS的REST API訪問代碼

Batch,打包多個請求

由于移動的特殊性(latency),一個頁面一般需要請求多次,才能render。請求多用異步,多個異步的嵌套挺不方便, 如果能合并這些請求,移動端的開發會更方便,也會提高性能。api-kit透明的實現了這一點。

ns com.kanzhun.api

struct Book {
    i32 id
    string title
    string isbn
    float32 price
    string description
}

struct NewestReq {
    i32 limit
    i32 offset
}

struct SearchBookReq {
    string q
    i32 limit
    i32 offset
}

@url(/books/newest)
@get
func list<Book> GetNewest(NewestReq req); // batch要求參數的個數僅為一個

@url(/books/search)
@get
func list<Book> SearchBook(SearchBookReq req);

// `batch` 為關鍵字
// GetNewest, SearchBook 都是函數名
// batch請求,和服務端是一次交互,客戶端發送一次請求給服務端

@url(/batch)
batch Batch(GetNewest, SearchBook)

生成的code

  1. 在服務器端透明的處理掉Batch請求
  2. 在客戶端生成名為Batch的函數,接受GetNewest的req,SearchBook的req,返回BatchResp

自動生成Android,iOS的REST API訪問代碼

自動生成Android,iOS的REST API訪問代碼

現在的狀態

  1. Android,iOS,服務端(servlet)已經完成,已測試。生成的code和手寫的代碼一樣,高效簡潔。
  2. 除去Batch,沒有任何的私有協議。這里采用的是大家熟悉的HTTP,JSON,RESTful。 事實上,api-kit也可以用來生成已有的restful api的客戶端code。
  3. Batch用了一點私有協議: 請求打包,post給服務器,服務器拆開,取出一個一個的請求,挨個調用,打包每個函數的返回值,返回客戶端。Batch的服務端邏輯,是自動生成的
  4. Api的定義文件,是個很好的文檔。api-kit把文檔,翻譯成了可以執行的代碼。代碼也是文檔。這會節約團隊之間的交流成本, 節約出來的時間,可以干更有意思的事情,比如曬曬太陽,喝喝咖啡,和奶奶聊聊天,聽她講故事。
  5. Rest API的url endpoint是什么,對于客戶端來說,變成了實現細節。客戶端變成僅關心 函數名,參數,返回值,而這些,IDE會給我們很好的幫助。
  6. 整個流程簡化為:定義api規范,服務器端實interface。客戶端的代碼已經生成好。大家思考的方式,變成函數,返回值,參數。 交流也就變為該調用哪個函數,某個參數是什么意思,參數名,函數名,在common sense的幫助下,不少也是self explained,這部分溝通也會省掉一些。

接下來的工作

  1. 可能我會想辦法做到透明的cache(生成cache的code),
  2. 支持其它語言,比如生成ajax調用的js code,用于支持網站開發,Python的客戶端(開發時的黑盒子測試)
  3. 生成go的服務器端代碼

我們正在招聘,需要Android和iOS工程師的加入,和我一組,開發看準網的App,為四億職場人服務。 請發簡歷 到 shenfeng at kanzhun dot com,請加入我們

原文鏈接: http://shenfeng.me/intro-api-kit.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!