網頁

2020/3/27

RESTful API 文字與代碼問題 code text mapping

上週某天前端工程師跑來說希望我回傳及接收的資料型態都能一致,問題情境如下。

原本後端程式的回應內容為字串,例如使用者登入的瀏覽器名稱(browser name),回傳的結果如下。

{
  "browser": "Chrome",
}

如此前端可將取得的瀏覽器名稱直接顯示在頁面。

前端得到瀏覽器名稱後會依此做進一步查詢,例如查詢該瀏覽器的歷史紀錄。而後端API是設計成接收自訂的瀏覽器代碼(browser code)整數而非名稱。代碼與瀏覽器的名稱由列舉(enum)維護如下。

Browser

package com.abc.demo.enumeration;

public enum Browser {

    UNKNOWN(0, "Unknown"),
    CHROME(1, "Chrome"),
    EDGE(2, "Edge"),
    FIREFOX(3,"Firefox"),
    IE(4, "Internet Explore"),
    OPERA(5, "Opera"),
    SAFARI(6, "Safari");

    private int code;
    private String name;

    Browser(int code, String name) {
        this.code = code;
        this.name = name;
    }

    // getters and setters
}

因此前端查詢瀏覽器的歷史紀錄時,依上述設計必須傳送瀏覽器代碼如下。

{
  "browser": 1,
}

後端收到代碼後再轉為列舉型態並依此從資料庫取得該瀏覽器的歷史紀錄。

但前端工程師抱怨為什麼第二次請求不改成也是傳字串像下面這樣,要不然前端又要想辦法把第一次查詢收到的名稱字串轉成代碼整數。

{
  "browser": "Chrome",
}

當時我回說送字串來的話可能會因為大小寫不同或空白造成比對錯誤導致查不出資料(例如"chrome""Chrome "),用整數比較明確,而且若字串很長效率也差吧。前端說這樣的話前端也要維護一個代碼名稱對應表,對應表應該在同一個地方維護就好。

當下我正在忙別的事,一時也想不出怎麼才是對,只覺得她說得沒錯(但很煩),而我說的也沒錯,反正最後就先依她的意思修改。

事後想了一下,認為前端第一次查詢登入的瀏覽器時,後端不應該只回傳名稱,應該也要回傳代碼如下。

{
  "browser": {
    "code": 1,
    "name": "Chrome"
  }
}

如此前端一來可顯式後端送來的名稱內容,也可從第一次查詢的json物件中取得代碼來進一步查詢。


參考以下包有各種型態的回應物件。

DemoResponse

package com.abc.demo.controller.response;

import com.abc.demo.controller.dto.BrowserDto;
import com.abc.demo.enumeration.Browser;

import java.util.Map;

public class DemoResponse {

    private String browserName;
    private Integer browserCode;
    private Browser browser;
    private BrowserDto browserDto;
    private Map<Integer, String> browserMap;

    // getters and setters...
}

package com.abc.demo.controller.dto;

import com.abc.demo.enumeration.Browser;

public class BrowserDto {

    private int code;
    private String name;

    public BrowserDto(Browser browser) {
        this.code = browser.getCode();
        this.name = browser.getName();
    }

    // getters and setters...
}

在Spring Boot Controller回傳如下。

DemoController

package com.abc.demo.controller;

import com.abc.demo.controller.dto.BrowserDto;
import com.abc.demo.controller.response.DemoResponse;
import com.abc.demo.enumeration.Browser;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class DemoController {

    @GetMapping(value = "/get/browser")
    public DemoResponse demo() {
        Browser browser = Browser.CHROME;
        DemoResponse demoResponse = new DemoResponse();
        demoResponse.setBrowserName(browser.getName());
        demoResponse.setBrowserCode(browser.getCode());
        demoResponse.setBrowser(browser);
        demoResponse.setBrowserDto(new BrowserDto(browser));
        demoResponse.setBrowserMap(Map.of(browser.getCode(), browser.getName()));

        return demoResponse;
    }

}

回傳物件傳成的json內容如下。

{
  "browserName":"Chrome",
  "browserCode":1,
  "browser":"CHROME",
  "browserDto":{
    "code":1,
    "name":"Chrome"
  },
  "browserMap":{
    "1":"Chrome"
  }
}

沒有留言:

張貼留言