Back to Basic of Fuel เขียนเรียก API แบบไม่ยุ่งยาก
คราวก่อนใช้ท่ายากไปนิดนึง ดูไม่ยืดหยุ่น แถมเจอหลายๆเคสเพิ่มเติมด้วย เลยกลายเป็นบล็อกตอนสองออกมา
ย้อนความเดิมตอนที่แล้ว เราได้ใช้ท่ายากในการทำ Routing Class เพื่อพูดคุยกับ API แต่แล้วเราค้นพบว่าการใช้งานในบางกรณีมันไม่ยืดหยุ่นเอาซะเลยนี่สิ แถมรู้สึกว่าเหมือนเราสร้าง 2 class คือ routing และ presenter แยกกันแบบเปลืองๆยังไงไม่รู้แหะ
ดังนั้นเราจึงต้องมา Back to Basic มาใช้แบบง่ายๆกันเถอะ
ถ้าจำบล็อกก่อนได้ (ถ้าไม่ได้อ่านข้ามตรงนี้ได้นะ)
เราบอกว่าใน Kotlin แนะนำให้ลองใช้ Fuel ซึ่งเรานำเสนอท่ายากไป ดังนั้น เราจึงเอามาเปรียบเทียบกับ Retrofit (ซึ่งลืมไปแล้วว่าเขียนยังไง ฮ่าๆ) ว่ามีอะไรเหมือนหรือต่างกัน
ซึ่งต่างกันที่ gateway ของ Retrofit และ routing ของ Fuel นั่นเอง เรียกง่ายๆว่าใช้ท่าไม่เหมือนกันนั่นเอง
เรามองว่าพอมาแยก class ส่วน Routing และ Presenter พบว่าเหมือนสร้าง class เยอะเกินความจำเป็นในส่วนของ Routing เลยจะรวบให้อยู่ใน Presenter ให้หมดซะเลย (เพราะไม่อยากให้โปรเจกมันบวมไปกว่านี้ บวกกับขี้เกียจหาเวลาต้องมาแก้อะไรบางอย่างใน Routing นั่นเอง ผ่ามมม) ซึ่งถ้าเทียบจำนวนบรรทัดแล้วคุ้มค่าต่อการลบ class Routing มาก ฮ่าๆ ดังนั้นเราค่อยๆย้ายมาอยู่ที่ Presenter ให้หมดเลย ดังรูปที่วาดน้ี
ซึ่งหน้าตาวิธีการย้ายนั้น ไม่ได้ยากอะไรนัก แบบในรูปนี้ ตัว Routing เป็น sealed class เนอะ ภายในประกอบได้ด้วย header, method, params และ path ถูกรวบไปเป็น sub-class ของ Routing class อีกทีนึง ตอน request
การทำ Fuel ขั้นพื้นฐาน (ถ้าไม่ได้อ่านบล็อกที่แล้ว เริ่มอ่านตรงนี้ได้จ้า)
เราสามารถใช้งาน Fuel ได้ไม่ยากเลยจ้า มีรูปแบบการใช้งานที่ดูเป็นมิตรแบบนี้
Fuel.<method>(<path>, <params>)
.header(<header>)
.responseObject(ModelClass.Deserializer()) {
...
}
- Method : หลักๆที่เราใช้มี Get, Post, Put นะ ซึ่งครอบคลุมนะ
- Path : url ของ API ที่เราเรียกใช้นั่นเอง
- Params : parameter นั่นเอง โดยเจ้านี่เป็น type
List<Pair<String, Any?>>?
วิธีการใส่ คือlistOf(“key” to “value”)
- Headers : ก็คือ header นั่นเอง ว่าเราจะใส่ค่าอะไรเข้าไป เช่น access token, api key หรือต่างๆนานา โดย headers จะต้องใส่เป็น type
Map<String, String>?
วิธีการใส่ คือmapOf(“key” to “value”)
จริงๆทั้งหมดทั้งมวลสามารถไปอ่านที่ library เขาได้เลยหนาาา
ลองมาสับเปลี่ยนกระบวนท่ากันเถอะ อันนี้สร้างแบบ basic ตามที่อธิบายตามขั้นต้น
อันนี้แบบยาก สร้าง class Routing กับ Presenter แยกกัน
หลังจากบล็อกที่แล้วที่เขียนเกี่ยวกับ Fuel เราก็ได้เจอหลากหลายตัวอย่างมากขึ้นนะ มีอะไรบ้างน๊อออ
การรับ data ก้อนนึงจาก backend มา แล้วเป็น ArrayList ของ Object ตัวนึง
อันนี้มีคนถามมาแล้ว ขอเล่าอีกรอบนึงแล้วกันเนอะ
สมมุติว่าได้ object ก้อนนึง เป็นประมาณนี้
{ "data": [{...}, {...}, {...}, ..., {...}]}
ซึ่งเจ้า {…}
ก็คือ class model ที่เราสร้างขึ้น แต่เจ้า response object ที่ได้คือ ArrayList ของ model นั้นๆหน่ะสิ เมื่อเราใส่ response object ผิด ชีวิตเปลี่ยนทันที แอป crash จ้า
ดังนั้นรับเจ้า response body ที่เป็น json
กันก่อน ด้วย responseJson
และแปลงเป็น ArrayList ของ model ตัวนึง นั่นคือ ArrayList<Data> ซึ่งในที่นี้ชื่อตัวแปรว่า data เพราะนึกชื่อไม่ออกแล้วนี่เอง
และอย่าลืมสร้างเจ้า listener class เพื่อนำมา handle case ต่างๆด้วยนะ
interface DataListener {
fun onLoadDataSuccess(video: ArrayList<Data>)
fun onLoadDataFailure(error: FuelError)
}
เท่านี้ก็เรียบร้อย ใช้งานได้ตามปกติสุขหล่ะ
ยัดก้อน body เป็น json ที่ขาเข้าแล้ว แต่ฝั่ง backend ไม่เห็นเป็น json ง่ะ
แยกเป็น 2 ประเด็น คือ ทำก้อน json ขึ้นมา กับใส่ Content-Type ให้เป็น json
บาง API อาจจะให้ frontend ยัดก้อน json เขาไปในส่วนของ body เนอะ ซึ่งการสร้างเจ้าก้อน json นั้นก็ไม่ได้ยากเท่าไหร่นัก
สมมุติแล้วกันว่า เรากด clap ในแอปอ่านบล็อกนึงที่คล้ายๆ medium ให้กับบทความนึง แล้วเราส่งเจ้า slug ของ blog และจำนวนที่เรา clap ดังนั้นเราสร้าง json
val json = JSONObject()
json.put(PARAM_CLAP_COUNT, shakesCount)
json.put(PARAM_BLOG_SLUG, slug)
พอมาใส่ใน function หนึ่งใน presenter class ก็จะเป็นแบบนี้
เราก็คิดว่ามันน่าจะจบแล้วเนอะ ยัดเจ้า body ไปแล้วอ่ะ run บนเครื่องเราน่าจะใช้ได้แล้วแหละ
แต่มันไม่เป็นแบบนั้นค่ะคุณณณณณณณณณณ เข้า failure จ้า
นี่นั่ง check กับ backend dev ว่าใส่ถูกไหม มันไม่น่าจะมีตรงไหนผิดหรอก แต่ๆๆๆๆ ตอนที่ฝั่ง backend ได้มานั้น ดั๊นนนน ไม่ใช่ type json หล่ะสิ ดันขึ้น Content-Type เป็น application/x-www-form-urlencoded
แทนที่จะเป็น application/json
หล่ะสิ
ดังนั้น เราต้องใส่เจ้า Content-Type ที่ header ด้วย เพื่อบอกว่าก้อนนี้เป็น json นะเว้ย แบบนี้
header(mapOf("Content-Type" to "application/json"))
ทั้งหมดทั้งมวลจะเป็นแบบนี้จ้า คราวนี้ก็จะถูกต้องสมบูรณ์แล้วจ้า รอดไปอีกหนึ่งที
upload file ไปให้ API
บางแอปอาจจะอัพอะไรบางอย่างขึ้นไป เช่น อัพรูป อัพวิดีโอ อัพไฟล์ อะไรแบบนี้ ซึ่งเจ้า Fuel สามารถเขียนเจ้า upload ได้แบบง่ายๆ สบายๆ ซึ่งไฟล์ที่รองรับก็น่าจะได้หมดนะ เท่าที่เห็นตัวอย่าง และมีหลายท่าด้วยนะ
สมมุติอัพรูปและวิดีโอขึ้นไปแล้วกันนะ ที่ใช้ท่า dataParts เพราะว่าเราอัพรูปและวิดีโอขึ้นไปเนอะ ซึ่งเราก็รู้ type และนามสกุลไฟล์ของมันอยู่แล้ว เราจึงสร้าง list ของ DataPart มาเพื่อให้เอาไฟล์จากในนี้เอาขึ้นไปหน่อยนะ ประมาณนี้
.dataParts { _, _ ->
listOf(DataPart(story, name = FILE_VIDEO, type = "video/mp4"),
DataPart(image, name = FILE_IMAGE, type = "image/jpeg"))
}
ในกรณีที่ internet ช้า และทำให้เข้า failure เนื่องจาก timeout เราก็สามารถ set timeout ได้นะเออ ซึ่งเจ้า timeout ใน Fuel จะมีให้ใช้ 2 ตัว เช่นกัน
timeout
: อันนี้ใช้ฝั่ง request เนอะtimeoutRead
: เจ้านี่มัน read ใช้กับ response
ซึ่งทั้งสองตัวนั้น จะมี default ที่ 15,000 ms คิดเป็น 15 วินาทีนั่นเอง
ดังนั้นการใช้งานก็แสนจะง่าย คือ เราสามารถกำหนดเวลาที่ timeout ซึ่งใส่เป็น parameter ได้แบบนี้
.timeoutRead(10 * 60 * 1000)
.timeout(10 * 60 * 1000)
เวลาใส่ก็ใส่ก่อน responseObject อะเนอะ ทั้งหมดทั้งมวลส่วน upload
ตอนนี้ก็ถือว่าน่าจะครบกระบวนท่าการใช้ Fuel เพียงเท่านี้ ก็ยาวพอสมควรเลยนะเนี่ย แต่เอาจริงๆบทความหรืออะไรต่างๆที่เกี่ยวกับ Fuel ก็น้อยเหลือเกิน
สุดท้ายฝากร้านกันสักนิด ฝากเพจด้วยนะจ๊ะ