09. August 2017

What is wrong with your API ?

API ဆိုတာက Data ကို အဓိကထားပြီး အသုံးပြုရတဲ့ Mobile App တွေအတွက်တော့ ကင်းလို့ရတဲ့အရာ မဟုတ်ပါဘူး။ API နဲ့ မချိတ်ထားတဲ့ APP ဆိုတာလည်း ဒီဘက်ခေတ်မှာ ခပ်ရှားရှားရယ်ပါ။ အဲတော့ Development လုပ်တဲ့အခါ Mobile Developer နဲ့ API Developer တွေ့ကြတာပါပဲ။ App က တစ်ခုခုပြဿနာဖြစ်ပြီဆို Mobile သမားကလည်း API ဘက်ကိုလွှဲချ API သမားကလည်း Mobile ဘက်ကိုလွှဲချနဲ့ လုံးချာလည်လိုက်ပြီး မကြာသင့်တာတွေ ကြာကုန်တယ်။ တကယ်တမ်း တစ်ဖက်စီက လုပ်ရကိုင်ရတဲ့ သဘောသဘာဝကို အနည်းအကျဉ်းနားလည်ထားတဲ့ အခါကျရင် အမှားနည်းတာပေါ့လေ။ မဟုတ်ရင် ကိုယ့်ဘက်မှာ ဒီလိုလုပ်လိုက်ရင် အဆင်ပြေပေမယ့် တစ်ဖက်မှာ အဆင်မပြေနိုင်ဘူးဆိုတာ မသိဘူး။ သတိမထားမိဘူး။ အဲတော့ လုပ်ပြီးသားပြန်ပြင်ရတယ်။ အချိန်ကုန်တယ်။ ပိုပင်ပန်းတယ်။ စိတ်မရှည်တော့ဘူး။ အဲတော့ အဆင်မပြေတော့ဘူးပေါ့။ ဒီနေရာမှာ သူငယ်ချင်းတစ်ယောက် ပြန်ဖြေတဲ့စကားတစ်ခွန်းကိုသွားသတိရတယ်။ သူက API ရေးတဲ့သူ .. Android ကို လေ့လာနေတယ်ဆိုလို့ လိုင်းပြောင်းတာ့မလို့လား မေးတာ့ .. မဟုတ်ဘူးကွတဲ့ ဘယ်လိုရေးလည်း သိထားတော့ မင်းတို့ Mobile Developer တွေ ဂျင်းထည့်တာ မခံရတော့ဘူးပေါ့ကွတဲ့။ ဟုတ်တယ် အဲလို သိထားရင် အနည်းဆုံးတော့ API ရေးတဲ့အခါ Mobile ဘက်ကနေ စဉ်းစားပြီးရေးတဲ့အတွက် ပိုဆင်ပြေတာပေါ့။ အဲဒါကြောင့် API ရေးတဲ့သူတွေ အဆင်ပြေအောင် ဖြစ်လေ့ရှိတဲ့ ပြဿနာတွေနဲ့ ဘာလို့အဲဒါတွေက Mobile ဘက်မှာ အဆင်မပြေလဲဆိုတာလေးကို ကြုံတုန်း စိတ်ထဲရှိနေတုန်း ချရေးထားတဲ့သဘောပါ။




Response Status Code


why always 200 ?



ပထမဆုံး response status code ကို အရင်ပြောရပါမယ်။ API က response ပြန်တဲ့အခါ API ကိုရောက်လာတဲ့ Request ကို process လုပ်ပြီး သင့်လျော်တဲ့ status code (ဥပမာ.. Authentication လိုအပ်တဲ့ Endpoint ကို request လုပ်တဲ့အခါ Authentication မပါလာရင် response status code က 401 Unauthorized) ပြန်ရပါမယ်။ ဘယ်လိုအနေအထားမှာ ဘယ်လို status code သုံးရမလဲဆိုတဲ့ Guideline ရှိပြီးသားပါ။ ဘာဖြစ်ဖြစ် အမြဲတမ်း 200 OK ပဲ ပြန်တဲ့အခါကျတော့ Mobile APP ဘက်က status code ကိုပဲ ကြည့်ပြီး ဆုံးဖြတ်လို့မရတော့ဘူး။ Coding အရလည်း meaningful မဖြစ်ဘူးပေါ့။ ကိုယ်ရေးထားတဲ့ code ကို ဘယ်သူလာဖတ်ဖတ် နားလည်ဖို့ဆိုတာ သတ်မှတ်ထားတဲ့ Standard တွေကို အသုံးချဖို့လည်း လိုပါတယ်။




Data Type Inconsistency

API ကရတဲ့ JSON Data တွေကို Android မှာ GSON, Jackson စတဲ့ JSON Parser/Converter တွေသုံးပြီးတော့ POJO (Plain Old Java Object) convert လုပ်ပစ်ပါတယ်။ အဲလို convert လုပ်ဖို့ JSON ထဲမှာပါလာမယ့် Key တွေကို POJO မှာ attribute တွေ အနေနဲ့ pre-defined လုပ်ထားရပါတယ်။ ဥပမာ.. API က ပြန်လာမယ့် data က ဒီလိုဆိုရင်



{
  "name": "Mg Mg",
  "age": 20,
  "skill": [
      "HTML",
      "CSS"
  ]
}

POJO ကို ဒီလိုပုံစံ ဆောက်ထားပါတယ်။



public class Address {

    private String name;

    private Integer age;

    private List<String> skill;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<String> getSkill() {
        return skill;
    }

    public void setSkill(List<String> skill) {
        this.skill = skill;
    }

}

အဲမှာ ဘာဖြစ်လဲဆိုတော့ တစ်ချို့တွေက Mg Mg မှာ skill ဆိုတဲ့ data မရှိရင် API က empty array မပြန်ပဲ false ဆိုပြီး ပြန်ပါတယ်။ တစ်ချို့က Empty String “” ပြန်ပါတယ်။ Array လို့ pre-defined လုပ်ထားတဲ့ skill ဆိုတဲ့ attribute ရဲ့ value က Boolean ဖြစ်လို့မရပါဘူး။ String ဖြစ်လို့မရပါဘူး။ Java က Statically typed language ဖြစ်တဲ့အတွက် String လို့ declare လုပ်ထားရင် String ပဲ assign လုပ်လို့ရပါတယ်။ String မဟုတ်ပဲ အခြား Data Type ဆို Error တက်ပါတယ်။ ဒါဆိုလည်း Assign မလုပ်ခင် type checking လုပ်ပြီးမှ assign လုပ်လို့ ပြောစရာရှိပါလိမ့်မယ်။ API က ရလာတဲ့ Data တစ်ခုချင်းစီရဲ့ Data Type တွေကို လိုက်မစစ်နိုင်ပါဘူး။ ဖြစ်လည်းမဖြစ်သင့်ပါဘူး။ မလိုအပ်ပဲ Mobile မှာ Processing မလုပ်တာ အကောင်းဆုံးပါ။ အဲတော့ API Documentation မှာ သတ်မှတ်ထားတဲ့ Data Type တွေ အတိုင်း String ဆိုလည်း data မရှိရင် Empty String “”, Array ဆိုလည်း Data မရှိရင် Empty Array [] ပဲဖြစ်သင့်ပါတယ်။




Nested Data Format

ဒါကတော့ မလိုအပ်ပဲ Data ကို အထပ်ထပ် wrap လုပ်ထားတဲ့ ကိစ္စပါ။ ထားပါတော့ “Username is required.” ဆိုတဲ့ error message ကို API ကယူပြီး Mobile မှာ ပြန်ပြမယ်ဆိုရင် ..



{
  "data": {
    "error": {
      "message": "Username is required."
    }
  }
}

API က အဲလိုပုံစံမျိုးပြန်တဲ့အခါကျတော့ Android ဘက်မှာ POJO ပြန်ဆောက်တဲ့အခါ ဒီလိုပုံဖြစ်သွားပါတယ်။



public class Response {

    private Data data;

    public Data getData() {
        return data;
    }

    public void setData(Data data) {
        this.data = data;
    }

}

public class Data {

    private Error error;

    public Error getError() {
        return error;
    }

    public void setError(Error error) {
        this.error = error;
    }

}

public class Error {

    private String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

}

message ပြန်ယူတဲ့အခါကျတော့လည်း



response.getData().getError().getMessage();

message လေး တစ်ကြောင်းပြဖို့ကို မလိုအပ်ပဲ Object တွေများပြီး Null Pointer Exception ပိုဖြစ်လွယ်ပါတယ်။ ရိုးရိုးရှင်းရှင်းနဲ့ ဒီလို format မျိုးပဲ ဖြစ်သင့်ပါတယ်။ 



{
      "message": "Username is required."
}


Dynamic Key

Dynamic Key ဆိုတာက API response ပြန်တဲ့ JSON ရဲ့ key က re-defined မဟုတ်ပဲ အရှင်ဖြစ်နေတာကို ဆိုလိုတာပါ။ အဲတော့ ဘယ်လိုမှ POJO ကို auto convert လုပ်မရတဲ့အတွက် ကိုယ့်ဘာသာ Custom Deserializer ရေးပြီး JSON ကို parse ရပါမယ်။ ပြီးမှ POJO ကိုပြန် convert ထပ်လုပ်ရပါမယ်။ အလုပ်တွေပိုကုန်ပါတယ်။ အဲဒါကြောင့် ဘာမှအထူးတလည် အကြောင်းပြချက်မရှိပဲနဲ့တော့ Dynamic Key ကို မသုံးသင့်ပါဘူး။



{
  "mg mg": 23,
  "aung aung": 20,
  "su su": 21
}

အဲလို Dynamic Key သုံးမယ့်အစား ..



[
  {
    "name": "mg mg",
    "age": 23
  },
  {
    "name": "aung aung",
    "age": 20
  },
  {
    "name": "su su",
    "age": 21
  }
]

ဒါဆိုရင် “name”, “age” ပါတဲ့ POJO (Student class ပဲထားပါတော့) တစ်ခုဆောက်လိုက်ပြီး List<Student> လို့ declare လုပ်လိုက်ရင် ဘာမှ ထပ်ရေးစရာမလိုပဲ အဆင်ပြေသွားပြီ။

#me #api #android