กำลังบันทึกข้อมูล

วิธีประหยัดอินเทอร์เน็ต

PUT เขียนหรือแทนที่ข้อมูลในเส้นทางที่กําหนด เช่น fireblog/users/user1/<data>
แพตช์ อัปเดตคีย์บางรายการสำหรับเส้นทางที่กําหนดไว้โดยไม่ต้องแทนที่ข้อมูลทั้งหมด
POST เพิ่มลงในรายการข้อมูลในฐานข้อมูล Firebase ทุกครั้งที่เราส่งคําขอ POST ไคลเอ็นต์ Firebase จะสร้างคีย์ที่ไม่ซ้ำกัน เช่น fireblog/users/<unique-id>/<data>
ลบ นําข้อมูลจากข้อมูลอ้างอิงฐานข้อมูล Firebase ที่ระบุออก

การเขียนข้อมูลด้วย PUT

การดำเนินการเขียนพื้นฐานผ่าน REST API คือ PUT เราจะสร้างแอปพลิเคชันการเขียนบล็อกที่มีโพสต์และผู้ใช้เพื่อสาธิตการบันทึกข้อมูล ข้อมูลทั้งหมดสำหรับแอปพลิเคชันจะจัดเก็บไว้ในเส้นทาง "fireblog" ที่ URL ฐานข้อมูล Firebase "https://docs-examples.firebaseio.com/fireblog"

มาเริ่มกันด้วยการบันทึกข้อมูลผู้ใช้บางส่วนลงในฐานข้อมูล Firebase เราจะจัดเก็บผู้ใช้แต่ละรายตามชื่อผู้ใช้ที่ไม่ซ้ำกัน รวมถึงจะจัดเก็บชื่อและนามสกุล รวมถึงวันเกิดของผู้ใช้ด้วย เนื่องจากผู้ใช้แต่ละรายจะมีชื่อผู้ใช้ที่ไม่ซ้ำกัน จึงควรใช้ PUT ที่นี่แทน POST เนื่องจากเรามีคีย์อยู่แล้วและไม่จำเป็นต้องสร้าง

เมื่อใช้ PUT เราจะเขียนสตริง ตัวเลข บูลีน อาร์เรย์ หรือออบเจ็กต์ JSON ใดก็ได้ลงในฐานข้อมูล Firebase ในกรณีนี้ เราจะส่งออบเจ็กต์ไปให้

curl -X PUT -d '{
  "alanisawesome": {
    "name": "Alan Turing",
    "birthday": "June 23, 1912"
  }
}' 'https://docs-examples.firebaseio.com/fireblog/users.json'

เมื่อบันทึกออบเจ็กต์ JSON ลงในฐานข้อมูล ระบบจะแมปพร็อพเพอร์ตี้ออบเจ็กต์กับสถานที่ตั้งย่อยโดยอัตโนมัติในลักษณะที่ซ้อนกัน หากไปยังโหนดที่สร้างขึ้นใหม่ เราจะเห็นค่า "Alan Turing" นอกจากนี้ เรายังบันทึกข้อมูลไปยังตำแหน่งของบุตรหลานโดยตรงได้ด้วย โดยทำดังนี้

curl -X PUT -d '"Alan Turing"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/name.json'
curl -X PUT -d '"June 23, 1912"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/birthday.json'

ตัวอย่าง 2 รายการข้างต้น ซึ่งได้แก่ การเขียนค่าพร้อมกันกับออบเจ็กต์และการเขียนค่าแยกไปยังตำแหน่งย่อย จะทำให้ระบบบันทึกข้อมูลเดียวกันลงในฐานข้อมูล Firebase

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    }
  }
}

คำขอที่สำเร็จจะแสดงด้วย200 OKรหัสสถานะ HTTP และการตอบกลับจะมีข้อมูลที่เราได้เขียนลงในฐานข้อมูล ตัวอย่างแรกจะทริกเกอร์เหตุการณ์เพียง 1 รายการในไคลเอ็นต์ที่ดูข้อมูลอยู่ ส่วนตัวอย่างที่ 2 จะทริกเกอร์ 2 รายการ โปรดทราบว่าหากมีข้อมูลอยู่ในเส้นทางของผู้ใช้อยู่แล้ว แนวทางแรกจะเขียนทับข้อมูลนั้น แต่วิธีที่ 2 จะแก้ไขเฉพาะค่าของโหนดย่อยแต่ละโหนดแยกกัน โดยไม่เปลี่ยนแปลงโหนดย่อยอื่นๆ PUT มีค่าเท่ากับ set() ใน JavaScript SDK

การอัปเดตข้อมูลด้วย PATCH

เมื่อใช้คำขอ PATCH เราจะอัปเดตเด็กที่เฉพาะเจาะจงในสถานที่หนึ่งๆ ได้โดยไม่ต้องเขียนทับข้อมูลที่มีอยู่ มาเพิ่มชื่อเล่นของ Turing ลงในข้อมูลผู้ใช้ด้วยPATCH คําขอต่อไปนี้

curl -X PATCH -d '{
  "nickname": "Alan The Machine"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

คําขอข้างต้นจะเขียน nickname ไปยังออบเจ็กต์ alanisawesome ของเราโดยไม่ลบออบเจ็กต์ย่อย name หรือ birthday โปรดทราบว่าหากเราออกคำขอ PUT ที่นี่แทน ระบบจะลบ name และ birthday ออกเนื่องจากไม่ได้รวมอยู่ในคำขอ ตอนนี้ข้อมูลในฐานข้อมูล Firebase มีลักษณะดังนี้

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    }
  }
}

คำขอที่สำเร็จจะแสดงด้วยรหัสสถานะ HTTP 200 OK และการตอบกลับจะมีข้อมูลที่อัปเดตแล้วซึ่งเขียนลงในฐานข้อมูล

นอกจากนี้ Firebase ยังรองรับการอัปเดตหลายเส้นทางด้วย ซึ่งหมายความว่าตอนนี้ PATCH สามารถอัปเดตค่าในตำแหน่งต่างๆ ในฐานข้อมูล Firebase ได้พร้อมกัน ซึ่งเป็นฟีเจอร์ที่มีประสิทธิภาพซึ่งช่วยให้คุณแปลงข้อมูลกลับเป็นรูปแบบปกติได้ เมื่อใช้การอัปเดตหลายเส้นทาง เราจะเพิ่มชื่อเล่นให้กับทั้ง Alan และ Grace ได้พร้อมกัน ดังนี้

curl -X PATCH -d '{
  "alanisawesome/nickname": "Alan The Machine",
  "gracehopper/nickname": "Amazing Grace"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

หลังจากการอัปเดตนี้ ทั้ง Alan และ Grace ต่างก็เพิ่มชื่อเล่นแล้ว

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

โปรดทราบว่าการพยายามอัปเดตออบเจ็กต์โดยการเขียนออบเจ็กต์ที่มีเส้นทางรวมอยู่ด้วยจะส่งผลให้เกิดลักษณะการทำงานที่แตกต่างออกไป มาดูกันว่าจะเกิดอะไรขึ้นหากเราพยายามอัปเดต Grace และ Alan ด้วยวิธีนี้

curl -X PATCH -d '{
  "alanisawesome": {"nickname": "Alan The Machine"},
  "gracehopper": {"nickname": "Amazing Grace"}
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

ซึ่งจะทําให้ลักษณะการทํางานแตกต่างออกไป กล่าวคือ การเขียนทับโหนด /fireblog/users ทั้งหมด

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

การอัปเดตข้อมูลด้วยคําขอแบบมีเงื่อนไข

คุณสามารถใช้คำขอแบบมีเงื่อนไข ซึ่งเป็น REST ที่เทียบเท่าธุรกรรม เพื่ออัปเดตข้อมูลตามสถานะที่มีอยู่ เช่น หากต้องการเพิ่มตัวนับการโหวตเห็นด้วย และต้องการให้จำนวนการโหวตเห็นด้วยหลายรายการพร้อมกันแสดงผลอย่างถูกต้อง ให้ใช้คําขอแบบมีเงื่อนไขเพื่อเขียนค่าใหม่ลงในตัวนับ แทนที่จะเขียน 2 ครั้งซึ่งจะเปลี่ยนตัวนับเป็นตัวเลขเดียวกัน คําขอเขียนรายการใดรายการหนึ่งจะดำเนินการไม่สําเร็จ จากนั้นคุณจะลองส่งคําขออีกครั้งโดยใช้ค่าใหม่ได้
  1. หากต้องการส่งคําขอแบบมีเงื่อนไขในตําแหน่งหนึ่ง ให้รับตัวระบุที่ไม่ซ้ำสําหรับข้อมูลปัจจุบัน ณ ตําแหน่งนั้น หรือ ETag หากข้อมูลมีการเปลี่ยนแปลงที่ตำแหน่งนั้น ETag ก็จะเปลี่ยนแปลงด้วย คุณขอ ETag ได้ด้วยวิธีใดก็ได้ที่ไม่ใช่ PATCH ตัวอย่างต่อไปนี้ใช้คําขอ GET
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    การเรียกใช้ ETag ในส่วนหัวโดยเฉพาะจะแสดงผล ETag ของตำแหน่งที่ระบุในการตอบกลับ HTTP
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    10 // Current value of the data at the specified location
  2. ใส่ ETag ที่แสดงผลในคำขอ PUT หรือ DELETE ถัดไปเพื่ออัปเดตข้อมูลที่ตรงกับค่า ETag นั้นโดยเฉพาะ จากตัวอย่าง หากต้องการอัปเดตตัวนับเป็น 11 หรือมากกว่าค่าที่ดึงข้อมูลครั้งแรก 10 หน่วย และทำให้คำขอไม่สําเร็จหากค่าไม่ตรงกันอีกต่อไป ให้ใช้โค้ดต่อไปนี้
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    หากค่าของข้อมูลที่ตำแหน่งที่ระบุยังคงเป็น 10 อยู่ ETag ในคำขอ PUT จะตรงกัน และคำขอจะสำเร็จโดยเขียน 11 ลงในฐานข้อมูล
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    Cache-Control: no-cache
    
    11 // New value of the data at the specified location, written by the conditional request
    หากตำแหน่งไม่ตรงกับ ETag อีกต่อไป ซึ่งอาจเกิดขึ้นหากผู้ใช้รายอื่นเขียนค่าใหม่ลงในฐานข้อมูล คำขอจะดำเนินการไม่สำเร็จโดยไม่มีการเขียนลงในตำแหน่ง การตอบกลับที่แสดงผลจะมีค่าใหม่และ ETag
    HTTP/1.1 412 Precondition Failed
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    12 // New value of the data at the specified location
  3. ใช้ข้อมูลใหม่นี้หากตัดสินใจที่จะส่งคำขออีกครั้ง Realtime Database จะไม่ลองส่งคำขอแบบมีเงื่อนไขที่ไม่สำเร็จอีกครั้งโดยอัตโนมัติ อย่างไรก็ตาม คุณสามารถใช้ค่าใหม่และ ETag เพื่อสร้างคำขอแบบมีเงื่อนไขใหม่ที่มีข้อมูลที่แสดงผลจากการตอบกลับที่ไม่สำเร็จ

คำขอแบบมีเงื่อนไขตาม REST ใช้มาตรฐาน HTTPif-match แต่มีความแตกต่างจากมาตรฐานดังนี้

  • คุณจะระบุค่า ETag ได้เพียงค่าเดียวสําหรับคําขอ if-match แต่ละรายการเท่านั้น
  • แม้ว่ามาตรฐานจะแนะนําให้แสดง ETag กับคําขอทั้งหมด แต่ Realtime Database จะแสดงเฉพาะ ETag กับคําขอที่มีส่วนหัว X-Firebase-ETag วิธีนี้ช่วยลดค่าใช้จ่ายในการเรียกเก็บเงินสำหรับคำขอมาตรฐาน

นอกจากนี้ คำขอแบบมีเงื่อนไขยังอาจช้ากว่าคำขอ REST ทั่วไปด้วย

การบันทึกรายการข้อมูล

หากต้องการสร้างคีย์ที่ไม่ซ้ำกันซึ่งอิงตามการประทับเวลาสำหรับรายการย่อยทุกรายการที่เพิ่มลงในข้อมูลอ้างอิงฐานข้อมูล Firebase เราส่งคำขอ POST ได้ สําหรับเส้นทาง users เราจึงควรกําหนดคีย์ของเราเองเนื่องจากผู้ใช้แต่ละรายมีชื่อผู้ใช้ที่ไม่ซ้ำกัน แต่เมื่อผู้ใช้เพิ่มบล็อกโพสต์ลงในแอป เราจะใช้คําขอ POST เพื่อสร้างคีย์ให้บล็อกโพสต์แต่ละรายการโดยอัตโนมัติ ดังนี้

curl -X POST -d '{
  "author": "alanisawesome",
  "title": "The Turing Machine"
}' 'https://docs-examples.firebaseio.com/fireblog/posts.json'

ตอนนี้เส้นทาง posts มีข้อมูลต่อไปนี้

{
  "posts": {
    "-JSOpn9ZC54A4P4RoqVa": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

โปรดทราบว่าระบบสร้างคีย์ -JSOpn9ZC54A4P4RoqVa ให้เราโดยอัตโนมัติเนื่องจากเราใช้คําขอ POST คำขอที่สำเร็จจะแสดงด้วยรหัสสถานะ HTTP 200 OK และการตอบกลับจะมีคีย์ของข้อมูลใหม่ที่เพิ่ม

{"name":"-JSOpn9ZC54A4P4RoqVa"}

การนำข้อมูลออก

หากต้องการนำข้อมูลจากฐานข้อมูลออก เราสามารถส่งคำขอ DELETE พร้อม URL ของเส้นทางที่ต้องการลบข้อมูล คำสั่งต่อไปนี้จะลบ Alan ออกจากเส้นทาง users

curl -X DELETE \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

คำขอ DELETE ที่สำเร็จจะแสดงด้วยรหัสสถานะ HTTP 200 OK พร้อมการตอบกลับที่มี JSON null

พารามิเตอร์ URI

REST API ยอมรับพารามิเตอร์ URI ต่อไปนี้เมื่อเขียนข้อมูลลงในฐานข้อมูล

การตรวจสอบสิทธิ์

พารามิเตอร์คำขอ auth อนุญาตให้เข้าถึงข้อมูลที่ Firebase Realtime Database Security Rules ปกป้องอยู่ และคำขอทุกประเภทรองรับพารามิเตอร์นี้ โดยอาร์กิวเมนต์อาจเป็นข้อมูลลับของแอป Firebase หรือโทเค็นการตรวจสอบสิทธิ์ ซึ่งเราจะกล่าวถึงในส่วนการให้สิทธิ์ผู้ใช้ ในตัวอย่างต่อไปนี้ เราส่งคําขอ POST ที่มีพารามิเตอร์ auth โดยที่ CREDENTIAL คือข้อมูลลับของแอป Firebase หรือโทเค็นการตรวจสอบสิทธิ์

curl -X POST -d '{"Authenticated POST request"}' \
  'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

พิมพ์

พารามิเตอร์ print ช่วยให้เราระบุรูปแบบของคำตอบจากฐานข้อมูลได้ การเพิ่ม print=pretty ลงในคําขอจะแสดงผลข้อมูลในรูปแบบที่มนุษย์อ่านได้ คำขอ GET, PUT, POST, PATCH และ DELETE รองรับ print=pretty

หากต้องการซ่อนเอาต์พุตจากเซิร์ฟเวอร์เมื่อเขียนข้อมูล เราเพิ่ม print=silent ลงในคำขอได้ การตอบกลับที่ได้จะว่างเปล่าและระบุด้วย204 No Contentรหัสสถานะ HTTP หากคําขอสําเร็จ คำขอ GET, PUT, POST และ PATCH รองรับ print=silent

การเขียนค่าเซิร์ฟเวอร์

ค่าเซิร์ฟเวอร์สามารถเขียนไว้ในตำแหน่งโดยใช้ค่าตัวยึดตําแหน่ง ซึ่งเป็นออบเจ็กต์ที่มีคีย์ ".sv" รายการเดียว ค่าของคีย์นั้นคือประเภทค่าเซิร์ฟเวอร์ที่เราต้องการตั้งค่า เช่น หากต้องการตั้งการประทับเวลาเมื่อสร้างผู้ใช้ เราอาจทําดังนี้

curl -X PUT -d '{".sv": "timestamp"}' \
  'https://docs-examples.firebaseio.com/alanisawesome/createdAt.json'

"timestamp" เป็นค่าเซิร์ฟเวอร์เพียงค่าเดียวที่รองรับ และเป็นเวลาที่นับจากยุค UNIX เป็นมิลลิวินาที

การปรับปรุงประสิทธิภาพการเขียน

หากเขียนข้อมูลจำนวนมากลงในฐานข้อมูล เราจะใช้พารามิเตอร์ print=silent เพื่อปรับปรุงประสิทธิภาพการเขียนและลดการใช้แบนด์วิดท์ได้ ในลักษณะการเขียนปกติ เซิร์ฟเวอร์จะตอบกลับด้วยข้อมูล JSON ที่เขียน เมื่อระบุ print=silent เซิร์ฟเวอร์จะปิดการเชื่อมต่อทันทีที่ได้รับข้อมูล ซึ่งจะช่วยลดการใช้แบนด์วิดท์

ในกรณีที่มีการส่งคำขอไปยังฐานข้อมูลหลายรายการ เราจะใช้การเชื่อมต่อ HTTPS ซ้ำได้โดยส่งคำขอ Keep-Alive ในส่วนหัว HTTP

เงื่อนไขข้อผิดพลาด

REST API จะแสดงรหัสข้อผิดพลาดในกรณีต่อไปนี้

รหัสสถานะ HTTP
400 คำขอไม่ถูกต้อง

เงื่อนไขข้อผิดพลาดอย่างใดอย่างหนึ่งต่อไปนี้

  • แยกวิเคราะห์ข้อมูล PUT หรือ POST ไม่ได้
  • ไม่มีข้อมูล PUT หรือ POST
  • คำขอพยายามPUTหรือPOSTข้อมูลที่มีขนาดใหญ่เกินไป
  • การเรียก REST API มีชื่อย่อยที่ไม่ถูกต้องเป็นส่วนหนึ่งของเส้นทาง
  • เส้นทางการเรียก REST API ยาวเกินไป
  • คำขอมีค่าเซิร์ฟเวอร์ที่ไม่รู้จัก
  • ไม่ได้กำหนดดัชนีสำหรับคำค้นหาใน Firebase Realtime Database Security Rules
  • คําขอไม่รองรับพารามิเตอร์การค้นหาที่ระบุไว้รายการใดรายการหนึ่ง
  • คําขอผสมพารามิเตอร์การค้นหาเข้ากับคําขอ GET แบบตื้น
401 ไม่ได้รับอนุญาต

เงื่อนไขข้อผิดพลาดอย่างใดอย่างหนึ่งต่อไปนี้

  • โทเค็นการตรวจสอบสิทธิ์หมดอายุแล้ว
  • โทเค็นการตรวจสอบสิทธิ์ที่ใช้ในคำขอไม่ถูกต้อง
  • ตรวจสอบสิทธิ์ด้วย access_token ไม่สำเร็จ
  • คำขอดังกล่าวละเมิดFirebase Realtime Database Security Rulesของคุณ
404 ไม่พบ ไม่พบฐานข้อมูล Firebase ที่ระบุ
500 ข้อผิดพลาดภายในเซิร์ฟเวอร์ เซิร์ฟเวอร์แสดงข้อผิดพลาด ดูรายละเอียดเพิ่มเติมได้ในข้อความแสดงข้อผิดพลาด
503 ไม่พร้อมให้บริการ ฐานข้อมูลเรียลไทม์ของ Firebase ที่ระบุไม่พร้อมใช้งานชั่วคราว ซึ่งหมายความว่าระบบไม่ได้พยายามส่งคำขอ

การรักษาความปลอดภัยของข้อมูล

Firebase มีภาษาด้านความปลอดภัยที่ช่วยให้เรากําหนดได้ว่าผู้ใช้รายใดมีสิทธิ์อ่านและเขียนโหนดข้อมูลต่างๆ อ่านข้อมูลเพิ่มเติมได้ใน Realtime Database Security Rules

เมื่อพูดถึงการบันทึกข้อมูลแล้ว เรามาเรียนรู้วิธีดึงข้อมูลจากฐานข้อมูล Firebase ผ่าน REST API กันต่อในส่วนถัดไป