[HTTP] การเขียน HTTP Status Codes โลกของความเป็นจริง เมื่อคุณเริ่มทำ API

สวัสดีครับบทคามนี้ผมจะมาอธิบายว่าการใส่ HTTP status codes นั่นมันสำคัญต่อการทำ API ยังไงในแง่ของการใช้งานจริง และถ้าไม่ใส่จะเป็นยังไง โดยผมจะยกตัวอย่างเหตุการณ์ง่ายๆ อย่างเช่นการทำเว็บมาให้เห็นภาพกัน และจุดประสงค์อีกอย่างนึงคือการอยากให้ทุกคนเขียนโปรแกรมให้เป็นมาตรฐานตรงตาม Standard ซึ่งก่อนหน้านี้ผมเคยเขียนบทความตัวนึงเกี่ยวกับการเขียน API ตาม Standard ไปแลยตามนี้ลิ้งนี้เลยครับ ก่อนจะมาเริ่มกันมาทำความรู้จักก่อนว่า HTTP status codes เริ่มกันเลย

 

HTTP status codes

HTTP status codes นั่นเป็นตัวเลขชุดนึงที่ประกอบไปด้วยตัวเลข 3 ตัว ไว้สำหรับการระบุว่าการ Request ครั่งนั่นมีสถานะเป็นยังไงบ้าง เกิด Error ไม่เจอ URL ไม่ได้ทำการ Authen หรือแม้กระทั่ง Server พัง ซึ่งปกติเราจะคุ้นเคยกันเป็นประจำจะได้เจอกันบ่อยๆ คือ 404 Page Not Found นั่นเอง HTTP status นั่นมีหลายตัวมาก แต่ผมไม่แนะนำให้ท่องจำทั่งหมดแต่วิธีการจำที่ถูกคือการจำว่าเลขตัวแรกนั่นอยู่หมวดหรือคลาสไหน นั่นเอง

 

Classes of Status

1×× Informational

Request เรานั้นได้ถูกรับไปประมวลผลแล้วและตอนนี้กำลังทำงานต่อไปยัง Process ถัดไป

2×× Success

คลาสนี้ Request เราถูกประมวลผลแล้วและการประมวลนั่นเสร็จสิ้น ไม่มี Error ใดๆ หรือพูดง่ายๆ ว่าเป็นการตอบพวกสถานะแบบ Success นั่นเอง ปกติคลาสนี้เราจะนิยมใช้ 200 เพื่อให้ขารับ Response จาก API รู้ว่าทำงานเสร็จแล้ว

3×× Redirection

Request ของเรานั่นถูกส่งต่อไปเพื่อประมวลผลที่อื่น หรือเรียกไปที่อื่นๆ เพื่อต้องทำให้ Process นั่นมันสำเสร็จ

4xx: Client Error

คลาสนี้จะเกิดขึ้นเมื่อมี Error เกิดข้ออาจจะเกิดจากการส่งข้อมูลของเการ Request มาผิด หรือ Syntax แม้กระทั่งว่าผิด URL นั่นเอง

5xx: Server Error

คลาสนี้ไว้แสดงถึงสถานะ Server ถ้ามีการส่งเลขในคลาสนี้ออกไปแสดงว่า Server นั่นมีปัญหาอะไรบางอย่าง

 

Implementation in Real world of Programming

ก่อนจะไปดูเรื่องว่าเราจะใช้ตัวเลขอะไรบ้างและเลขไหนมันควรใช้ใน HTTP status ผมจะมาสอนว่าโลกความจริงของการการเขียนโปรแกรมนั่นเราจะป้องกัน BUG ที่เกิดจากการไม่ใส่ HTTP status นั่นมันเป็นยังไง ผมเชื่อว่าหลายๆ คนต้องเคยเจอมาโดยเฉพาะคนที่ทำ API บ่อยๆ มาดูตัวอย่างกัน bug มันจะมาเกิดกับระบบได้ยังไง 

 

Client

ตัวอย่างการเขียน Ajax Jquery ที่ถูกต้องควรจะเป็นแบบนี้ จริงๆ การเขียนโค้ดไม่มีถูกผิด ทำงานได้มันก็คือถูก ถ้าพูดแบบนั่นก็ไม่ผิด แต่ทำไมผมถึงพูดว่ามันถูกต้องสำหรับโค้ดนี้ เพราะมันมี success และ error callback ไงละ นั่นละนิยามคำว่าถูกของผม เดียวเราค่อยๆ มาดูกันว่าถูกคนจะเห็นด้วยไหม หรือใครถนัดใช้พวก $.post หรือ $.get อันนี้ก็ใช้ได้เหมือนกันแต่อย่าลืมทำ callback ก็พอ

 

Server

ตัวอย่างโค้ดการเขียน API ด้วย Ruby On Rail ใครที่ไม่เคยเขียนไม่เป็นไรครับ อ่านไม่ยากผมจะอธิายให้ฟังง่ายๆ ตัวอย่างนี้คือแค่ไปเรียก ORM ของ User model เพื่อไปดึงเอาข้อมูลใน table user มาแสดงผลเท่านั่นเอง จากนั่นใช้คำสั่ง render เพื่อโยน json ออกมาที่ client

 

ผลที่ได้ถ้าเอาทั่ง Server-Client มาประกอบกันมันก็จำทำงานได้ปกติ ซึ่งผมจะบอกว่าสิ่งที่มันควรจะเป็น เพราะมันประกอบด้วย

  1. Client มีตัวรับ callback ทั่ง success และ error case จาก server
  2. Server มีการตั้งค่า HTTP status ก่อนส่งข้อมูลในที่นี้ผมใช้ 200 เพราะเป็นการบอกว่า response นี้สำเร็จและไม่มี error เกิดขึ้นในกระบวนการ process

ที่นี่เราะจะมาดูวิธีที่หลายๆ คนเคยทำในแบบที่ไม่ใช้ HTTP status ซึ่งเมื่อก่อนผมเองก็ยังเคยทำ

ผมเพิ่ม API ใหม่เข้าไปคือให้ไปดึง Post จาก database ด้วย ID ของ Post นั่น โดยผมเพิ่มเงื่อนไขว่าถ้า ไม่มีการส่ง parameter ID เข้ามาให้ response กลับไปทันทีและจะสังเกตได้ว่าผมเปลี่ยน success: false และเอาคำสั่งการใส่ค่า header ก่อนหน้านี้ออกไป แบบว่าทุกๆ การ render ในการเขียนรูปแบบนี้ HTTP status จะได้ 200 ตลอด แต่เราเอา flag success มาเป็นตัวกำหนดการทำงานของระบบแทน

 

ที่นี้ส่วนของ Client ผมแก้ใหม่นิดหน่อยและเพิ่ม comment ให้อ่าน และผลการทำงานของการเอา server-client ชุดบนกับชุดนี้มาประกอบกันคือ มันจะเข้า success case ตลอด แม้ว่า server จะบอกว่า success: false นะ เพราะในความหมายของคนเขียนมันคือ error ที่เกิดจากลืมส่ง ID มา เราก็เลยบอกมันว่ามัน false แต่ในความหมายการทำงาน HTTP นั่นมันก็ยังคงเป็น 200 ตลอด (ถ้าไม่ใส่ปกติมันจะตั้ง 200 ให้) ทำให้ error นั่นไม่ทำงานเลย จนกว่าจะเกิด status ในคลาส 5xx หรือ 4xx เท่านั่น ตรงนี้ที่สร้าง BUG หรือบ้างที่ทำให้ต้อง duprecate มาดูตัวอย่างต่อไป

 

ตัวอย่างนี้ ผมตั่งใจทำให้ error เกิดกับ Server และจะได้ 500 Internal Server Error ทำให้ระบบเราหยุดทำงานในฝั่ง server เพราะผมไม่ได้ใส่สัญญาลักษณ์คอมเม้นของ Ruby ลงไปในบรรทัดที่ 6

 

ผมสร้าง client ตัวใหม่มาอีกอันเพื่อแสดงให้เห็นว่าระบบเราเริ่มบัค คือพอ Server ตอบ 500 กลับมาบรรทัดที่ 15 มันจะทำงานทั่งๆ ที่มันไม่ได้เกี่ยวกับ comment ID ไม่ได้ใส่ และบรรทัดที่ 16 สมมุติเราก็มีการเขียนโค้ดจัดการ error ไว้ กลับกลายเป็นว่ามันไม่ได้ error แบบที่ควรจะเป็นอาจจะทำให้ client มันหยุดทำงานเพราะ data ที่ได้รับมามันผิด และเราก็จะคาดหวังว่าถ้ามัน error มันควรจะเข้า else บรรทัดที่ 9 ถ้ามีความผิดพลาดอะไรก็ตาม ซึ่งผมพูดในกรณีที่เราไม่ได้เปิด console เพื่อเช็คว่า server ตอบไรกลับมา มันก็จะทำให้ยากต่อการแก้บัค แถมโค้ดยังกระจัดกระจาย แทนที่ตัวจัดการ error มันควรจะอยู่ callback error ทั่งหมดไม่ว่ามันจะ 500, 400, 404 หรืออะไรก็ตาม เพื่อง่ายต่อการค้นหาบัคและแก้มัน เดี๋ยวเรามาดูอีกสักตัวอย่าง

 

ตัวอย่างนี้ผมได้ใส่ status ไว้คือ 400 คือ Bad Request ประมาณว่าการประมวลผลพบข้อผิดพลาดหรือเจอสิ่งที่ไม่ถูกต้อง ซึ่งปกติผมจะใส่ 400 ตลอด ถ้ากลับไปดู ajax อันแรกสุดที่ผมยกตัวอย่างไป ถ้ามันเช็ดว่าไม่มีการส่ง ID มาระบบจะตีกลับไปและ ajax มันจะ ทำงานใน error callback ที่นี่เราก็เขียนโค้ดจัดการ error ที่เกิดขึ้นได้ มาดูตัวอย่าง Client ด้านหลังกัน

 

สำหรับ Client นั่นผมก็ยกเอาอันบนมาแก้ใหม่จะเห็นว่าโค้ดเรานั่น Clean ขึ้นเยอะไม่ต้องมาเช็ค success อีก และก็การจัด error มันก็ไปกองอยู่ส่วนที่มันควรจะเป็น และเมื่อวันนึง server เป็นจาก success: false หรือ success: true เป็น 0,1 เราก็ไม่ต้องแก้โค้ดส่วนนี้เพราะเราอิงจาก HTTP status แถมโค้ดดูง่ายด้วย แต่ส่วนที่เป็น 500 จากด้านบนก็ยัง error ต่อไป และเรายังเขียนโค้ดเพิ่มได้อีกด้วยว่าถ้า เข้า error callback แล้วได้โค้ด 500 มาจะให้มันทำอะไร หรือเราจะไล่เช็คว่าได้โค้ดในคลาส 4xx, 5xx มาแล้วก็จะจัดการ error แบบไหนได้ด้วย

 

สงสัยใหม่ว่าทำไมผมถึงต้องใส่ success ไว้แบบด้านหลังทั่งๆ ที่เราก็อิงจาก HTTP status แล้ว ในความคิดของผมนั่นบางครั่งเราต้องการโยนข้อมูลไปประมวลผลที่อื่นทั่งก้อน และบางครั่งเราไม่ได้สั่งการทำงานมันจบใน callback ที่เดียว แต่เราอาจจะไปเรียกอีก 3-4 ฟังก์ชั่นกว่าจะได้โชว์ข้อมูลเพราะงั่นการใส่ success ไว้จึงเผื่อการทำงานเอาไว้ไปใช้ที่อื่นได้ เพราะตอนที่เราโยนข้อมูลไปตัว HTTP status มันไม่ได้ติดไปด้วยไงครับ หรือบางทีเราอาจจะออกแบบ API เป็นแบบ REST เพียวๆ และแยกเอา HTML ไว้อีก server  หรือทำ micro service เรียกผ่าน Server to Server และยังเอาไปให้ mobile เรียกต่อได้ด้วย บางที mobile ก็ไม่ได้ใช้ HTTP status มาช่วยเท่าที่ผมเคยทำงานกับ Mobile Dev ไม่ลืมทำ ก็คงขี้เกียจเพราะงั้นใส่ไว้แบบนี้ก็ไม่เสียหายอะไร เอาไปใช้ได้หลายแบบ

 

HTTP Status codes อะไรที่ใช้บ่อยสุด

สำหรับ Status นั่นมีเยอะมาก ผมเองก็ไม่มานั่งจำเหมือนกันปกติเปิด Google เอา ถ้าใครอยากรู้มีอะไรบางก็ลองอ่านที่ลิ้งนี้ดู link แต่ปกติแล้วผมก็ใช้ประมาณนี้

จริงๆ ผมใช้เยอะกว่านี้ แต่ผมตัดออกให้ เอาที่ทั่วๆ ไปใช้กับงานไม่สับซ้อน คัดมาให้ดู จริงๆ มันมีเรื่อง Payment ด้วยก็จะมี code ของมัน ถ้าใครอยากใช้หลายๆ โค้ดให้ตรงกับงานก็ลองไปดูลิ้งที่ผมแปะให้ด้านบนและลองหัดใช้ดูครับ

สุดท้ายนี้ผมอยากจะฝากไว้คือไม่ว่าจะออกแบบระบบอะไรหรือเขียน Framework อะไรให้ทำตาม Standard ที่เขาแนะนำกันไว้  อย่าแต่แค่ผ่านรันได้ เพราะจะได้ไม่เสียเวลาในการ refactor code มากหนัก แถมยังง่ายต่อการดูแลรักษาด้วยครับ

Facebook Comments