วิธีบันทึกข้อมูลโมเดล Backbone.js


86

ฉันสนใจการพัฒนาส่วนหน้ามากขึ้นและเพิ่งเริ่มสำรวจ Backbone.js ในแอปของฉัน ฉันต้องการคงข้อมูลโมเดลไว้ที่เซิร์ฟเวอร์

คุณช่วยอธิบายวิธีต่างๆในการบันทึกข้อมูล Model (โดยใช้รูปแบบ json) ฉันใช้ Java บนฝั่งเซิร์ฟเวอร์ นอกจากนี้ฉันยังเห็นว่าส่วนใหญ่ใช้ REST เพื่อบันทึกข้อมูล เนื่องจากฉันเป็นนักพัฒนาส่วนหน้ามากขึ้นฉันจึงไม่ทราบถึง REST และสิ่งอื่น ๆ ที่คล้ายคลึงกัน

จะดีมากถ้ามีใครช่วยอธิบายขั้นตอนให้ฉันฟังด้วยตัวอย่างง่ายๆ

คำตอบ:


272

โดยทั่วไปโมเดลมีคุณสมบัติที่เรียกว่าแอตทริบิวต์ซึ่งเป็นค่าต่างๆที่โมเดลบางรุ่นอาจมี Backbone ใช้ออบเจ็กต์ JSON เป็นวิธีง่ายๆในการเติมค่าเหล่านี้โดยใช้วิธีการต่างๆที่ใช้อ็อบเจ็กต์ JSON ตัวอย่าง:

Donuts = Backbone.Model.extend({
    defaults: {
        flavor: 'Boston Cream',  // Some string
        price: '0.50'  // Dollars
    }
});

ในการเติมโมเดลมีสองสามวิธีในการทำเช่นนั้น ตัวอย่างเช่นคุณสามารถตั้งค่าอินสแตนซ์โมเดลของคุณโดยส่ง JSON หรือใช้เมธอดที่เรียกว่า set () ซึ่งรับอ็อบเจ็กต์ JSON ของแอ็ตทริบิวต์

myDonut = new Donut({'flavor':'lemon', 'price':'0.75'});
mySecondHelping = new Donut();
mySecondHelping.set({'flavor':'plain', 'price':'0.25'});

console.log(myDonut.toJSON());
// {'flavor':'lemon', 'price':'0.75'}
console.log(mySecondHelping.toJSON());
// {'flavor':'plain', 'price':'0.25'}

ดังนั้นสิ่งนี้จึงนำเราไปสู่การประหยัดโมเดลและคงอยู่กับเซิร์ฟเวอร์ มีรายละเอียดมากมายเกี่ยวกับ "REST / RESTful คืออะไร" และเป็นเรื่องยากที่จะอธิบายทั้งหมดนี้ในคำประกาศสั้น ๆ ที่นี่ โดยเฉพาะอย่างยิ่งเกี่ยวกับการประหยัด REST และ Backbone สิ่งที่ต้องคำนึงถึงคือความหมายของคำขอ HTTP และสิ่งที่คุณกำลังทำกับข้อมูลของคุณ

คุณอาจคุ้นเคยกับคำขอ HTTP สองประเภท รับและโพสต์ ในสภาพแวดล้อมที่สงบคำกริยาเหล่านี้มีความหมายพิเศษสำหรับการใช้งานเฉพาะที่ Backbone ถือว่า เมื่อคุณต้องการรับทรัพยากรบางอย่างจากเซิร์ฟเวอร์ (เช่นโมเดลโดนัทที่ฉันบันทึกไว้ครั้งล่าสุดรายการบล็อกข้อกำหนดของคอมพิวเตอร์) และทรัพยากรนั้นมีอยู่คุณจะต้องร้องขอ GET ในทางกลับกันเมื่อคุณต้องการสร้างทรัพยากรใหม่คุณใช้ POST

ก่อนที่ฉันจะเข้าสู่ Backbone ฉันไม่เคยแตะวิธีการร้องขอ HTTP สองวิธีต่อไปนี้เลย วางและลบ คำกริยาทั้งสองนี้มีความหมายเฉพาะกับ Backbone เมื่อคุณต้องการอัปเดตทรัพยากร (เช่นเปลี่ยนรสชาติของโดนัทเลมอนเป็นโดนัทลิมอน ฯลฯ ) คุณจะใช้คำขอ PUT เมื่อคุณต้องการลบโมเดลนั้นออกจากเซิร์ฟเวอร์พร้อมกันคุณใช้คำร้องขอ DELETE

พื้นฐานเหล่านี้มีความสำคัญมากเนื่องจากแอป RESTful ของคุณคุณอาจมีการกำหนด URI ที่จะทำงานที่เหมาะสมตามชนิดของคำกริยาคำขอที่คุณใช้ ตัวอย่างเช่น:

// The URI pattern
http://localhost:8888/donut/:id

// My URI call
http://localhost:8888/donut/17

ถ้าฉันสร้าง GET เป็น URI นั้นมันจะได้รับโมเดลโดนัทที่มี ID เป็น 17 รหัส: id ขึ้นอยู่กับว่าคุณจะบันทึกมันในฝั่งเซิร์ฟเวอร์อย่างไร นี่อาจเป็นเพียง ID ของทรัพยากรโดนัทของคุณในตารางฐานข้อมูลของคุณ

ถ้าฉันทำการ PUT กับ URI นั้นด้วยข้อมูลใหม่ฉันจะทำการอัปเดตและบันทึกข้อมูลนั้น และถ้าฉันลบไปที่ URI นั้นมันจะลบออกจากระบบของฉัน

ด้วย POST เนื่องจากคุณยังไม่ได้สร้างทรัพยากรจึงไม่มี ID ทรัพยากรที่กำหนด บางทีเป้าหมาย URI ที่ฉันต้องการสร้างทรัพยากรเป็นเพียงแค่นี้:

http://localhost:8888/donut

ไม่มีส่วนของ ID ใน URI การออกแบบ URI ทั้งหมดนี้ขึ้นอยู่กับคุณและวิธีคิดเกี่ยวกับทรัพยากรของคุณ แต่เกี่ยวกับการออกแบบ RESTful ความเข้าใจของฉันคือคุณต้องการให้คำกริยาของการกระทำของคุณกับคำขอ HTTP และทรัพยากรเป็นคำนามซึ่งทำให้ URI อ่านง่ายและเป็นมิตรกับมนุษย์

คุณยังอยู่กับฉันไหม :-)

ลองกลับมาคิดถึง Backbone กระดูกสันหลังเป็นสิ่งที่ยอดเยี่ยมเพราะมันทำงานให้คุณได้มากมาย ในการช่วยโดนัทและวินาทีของเราเราเพียงแค่ทำสิ่งนี้:

myDonut.save();
mySecondHelping.save();

กระดูกสันหลังเป็นสมาร์ท หากคุณเพิ่งสร้างทรัพยากรโดนัททรัพยากรจะไม่มี ID จากเซิร์ฟเวอร์ มีสิ่งที่เรียกว่า cID ซึ่งเป็นสิ่งที่ Backbone ใช้ภายใน แต่เนื่องจากไม่มี ID อย่างเป็นทางการจึงรู้ว่าควรสร้างทรัพยากรใหม่และจะส่งคำขอ POST หากคุณได้รับโมเดลของคุณจากเซิร์ฟเวอร์โมเดลนั้นอาจมี ID หากทุกอย่างถูกต้อง ในกรณีนี้เมื่อคุณบันทึก () Backbone จะถือว่าคุณต้องการอัปเดตเซิร์ฟเวอร์และจะส่ง PUT หากต้องการรับทรัพยากรเฉพาะคุณจะต้องใช้เมธอด Backbone .fetch () และจะส่งคำขอ GET เมื่อคุณเรียก. Destroy () ในแบบจำลองระบบจะส่ง DELETE

ในตัวอย่างก่อนหน้านี้ฉันไม่เคยบอก Backbone อย่างชัดเจนว่า URI อยู่ที่ไหน ลองทำในตัวอย่างถัดไป

thirdHelping = Backbone.Model.extend({
    url: 'donut'
});
thirdHelping.set({id:15});  // Set the id attribute of model to 15
thirdHelping.fetch();  // Backbone assumes this model exists on server as ID 15

Backbone จะได้รับความช่วยเหลือที่สามhttp://localhost:8888/donut/15เพียงแค่เพิ่ม / donut stem ลงในรูทไซต์ของคุณ

ถ้าคุณยังอยู่กับฉันก็ดี ฉันคิด. เว้นแต่คุณจะสับสน แต่เราจะย่ำต่อไป ส่วนที่สองนี้คือด้านเซิร์ฟเวอร์ เราได้พูดถึงคำกริยาต่างๆของ HTTP และความหมายเชิงความหมายที่อยู่เบื้องหลังคำกริยาเหล่านั้น ความหมายที่คุณ Backbone และเซิร์ฟเวอร์ของคุณต้องแบ่งปัน

เซิร์ฟเวอร์ของคุณจำเป็นต้องเข้าใจความแตกต่างระหว่างคำขอ GET, POST, PUT และ DELETE ดังที่คุณเห็นในตัวอย่างด้านบน GET, PUT และ DELETE สามารถชี้ไปที่ URI เดียวกันhttp://localhost:8888/donut/07เว้นแต่เซิร์ฟเวอร์ของคุณสามารถแยกความแตกต่างระหว่างคำขอ HTTP เหล่านี้ได้ก็จะสับสนมากว่าจะทำอย่างไรกับทรัพยากรนั้น

นี่คือเมื่อคุณเริ่มคิดถึงรหัสสิ้นสุดเซิร์ฟเวอร์ RESTful ของคุณ บางคนชอบ Ruby, บางคนชอบ. net, ชอบ PHP โดยเฉพาะผมชอบ SLIM PHP micro-framework SLIM PHP เป็นไมโครเฟรมเวิร์กที่มีชุดเครื่องมือที่หรูหราและเรียบง่ายสำหรับจัดการกับกิจกรรม RESTful คุณสามารถกำหนดเส้นทาง (URI) เหมือนในตัวอย่างด้านบนและขึ้นอยู่กับว่าการเรียกนั้นเป็น GET, POST, PUT หรือ DELETE ซึ่งจะเรียกใช้รหัสที่ถูกต้อง มีโซลูชันอื่นที่คล้ายกับ SLIM เช่น Recess, Tonic ฉันเชื่อว่าเฟรมเวิร์กที่ใหญ่กว่าเช่น Cake และ CodeIgniter ก็ทำสิ่งที่คล้ายกันแม้ว่าฉันจะชอบมินิมอลก็ตาม ฉันบอกว่าฉันชอบสลิมหรือเปล่า? ;-)

นี่คือสิ่งที่รหัสที่ตัดตอนมาบนเซิร์ฟเวอร์อาจมีลักษณะ (กล่าวคือเฉพาะเกี่ยวกับเส้นทาง)

$app->get('/donut/:id', function($id) use ($app) {
    // get donut model with id of $id from database.
    $donut = ...

    // Looks something like this maybe:
    // $donut = array('id'=>7, 'flavor'=>'chocolate', 'price'=>'1.00')

    $response = $app->response();
    $response['Content-Type'] = 'application/json';
    $response->body(json_encode($donut));
});

โปรดทราบว่า Backbone ต้องการออบเจ็กต์ JSON ที่นี่ ให้เซิร์ฟเวอร์ของคุณกำหนดประเภทเนื้อหาเป็น 'application / json' และเข้ารหัสในรูปแบบ json เสมอหากทำได้ จากนั้นเมื่อ Backbone ได้รับอ็อบเจ็กต์ JSON จะรู้วิธีเติมข้อมูลโมเดลที่ร้องขอ

ด้วย SLIM PHP เส้นทางจะทำงานคล้ายกับข้างต้น

$app->post('/donut', function() use ($app) {
    // Code to create new donut
    // Returns a full donut resource with ID
});
$app->put('/donut/:id', function($id) use ($app) {
    // Code to update donut with id, $id
    $response = $app->response();
    $response->status(200);  // OK!
    // But you can send back other status like 400 which can trigger an error callback.
});
$app->delete('/donut/:id', function($id) use ($app) {
    // Code to delete donut with id, $id
    // Bye bye resource
});

คุณเกือบจะได้เที่ยวครบแล้ว! ไปรับโซดา ฉันชอบไดเอทเมาเท่นดิว รับหนึ่งสำหรับฉันด้วย

เมื่อเซิร์ฟเวอร์ของคุณประมวลผลคำขอดำเนินการบางอย่างกับฐานข้อมูลและทรัพยากรเตรียมการตอบกลับ (ไม่ว่าจะเป็นหมายเลขสถานะ http ธรรมดาหรือทรัพยากร JSON แบบเต็ม) จากนั้นข้อมูลจะกลับมาที่ Backbone สำหรับการประมวลผลขั้นสุดท้าย

ด้วยวิธีการ save (), fetch () และอื่น ๆ ของคุณคุณสามารถเพิ่มการเรียกกลับที่เป็นทางเลือกสำหรับความสำเร็จและข้อผิดพลาด นี่คือตัวอย่างของการตั้งค่าเค้กนี้โดยเฉพาะ:

Cake = Backbone.Model.extend({
    defaults: {
        type: 'plain',
        nuts: false
    },
    url: 'cake'
});

myCake = new Cake();
myCake.toJSON()  // Shows us that it is a plain cake without nuts

myCake.save({type:'coconut', nuts:true}, {
    wait:true,
    success:function(model, response) {
        console.log('Successfully saved!');
    },
    error: function(model, error) {
        console.log(model.toJSON());
        console.log('error.responseText');
    }
});

// ASSUME my server is set up to respond with a status(403)
// ASSUME my server responds with string payload saying 'we don't like nuts'

มีสองสิ่งที่แตกต่างกันเกี่ยวกับตัวอย่างนี้ คุณจะเห็นว่าสำหรับเค้กของฉันแทนที่จะ set () ในแอตทริบิวต์ก่อนบันทึกฉันเพียงแค่ส่งแอตทริบิวต์ใหม่ไปยังบันทึกการโทรของฉัน Backbone เป็นนินจาที่รับข้อมูล JSON ไปทั่วทุกที่และจัดการได้อย่างแชมป์ ดังนั้นฉันต้องการประหยัดเค้กของฉันด้วยมะพร้าวและถั่ว (นั่นคือถั่ว 2 เม็ดหรือเปล่า) อย่างไรก็ตามฉันส่งผ่านวัตถุสองชิ้นไปยังบันทึกของฉัน แอตทริบิวต์ออบเจ็กต์ JSON และอ็อพชันบางอย่าง อย่างแรก {wait: true} หมายถึงอย่าอัปเดตโมเดลฝั่งไคลเอ็นต์ของฉันจนกว่าการเดินทางฝั่งเซิร์ฟเวอร์จะสำเร็จ การเรียกกลับความสำเร็จจะเกิดขึ้นเมื่อเซิร์ฟเวอร์ส่งคืนการตอบกลับสำเร็จ อย่างไรก็ตามเนื่องจากตัวอย่างนี้ส่งผลให้เกิดข้อผิดพลาด (สถานะอื่นที่ไม่ใช่ 200 จะระบุให้ Backbone ใช้การเรียกกลับข้อผิดพลาด) เราจึงได้รับการเป็นตัวแทนของโมเดลโดยไม่มีการเปลี่ยนแปลง มันควรจะเป็นแบบธรรมดาและไม่มีถั่ว เรายังสามารถเข้าถึงวัตถุข้อผิดพลาดที่เซิร์ฟเวอร์ส่งกลับมา เราส่งสตริงกลับไป แต่อาจเป็นออบเจ็กต์ข้อผิดพลาด JSON ที่มีคุณสมบัติมากกว่า ซึ่งอยู่ในแอตทริบิวต์ error.responseText ใช่ 'เราไม่ชอบถั่ว'

ยินดีด้วย. คุณได้เดินทางไปกลับเต็มรูปแบบครั้งแรกของคุณจากการตั้งค่าแบบจำลองการบันทึกทางฝั่งเซิร์ฟเวอร์และกลับ ฉันหวังว่ามหากาพย์คำตอบนี้จะช่วยให้คุณมีความคิดว่าทั้งหมดนี้มารวมกันได้อย่างไร แน่นอนว่ามีรายละเอียดมากมายที่ฉันผ่านมา แต่แนวคิดพื้นฐานของการบันทึก Backbone, คำกริยา RESTful, การกระทำฝั่งเซิร์ฟเวอร์, การตอบสนองอยู่ที่นี่ อ่านเอกสาร Backbone ต่อไป (ซึ่งอ่านง่ายมากเมื่อเทียบกับเอกสารอื่น ๆ ) แต่โปรดทราบว่าการทำเช่นนี้ต้องใช้เวลาพอสมควร ยิ่งคุณเก็บไว้ได้มากเท่าไหร่คุณก็จะยิ่งคล่องมากขึ้นเท่านั้น ฉันเรียนรู้สิ่งใหม่ ๆ ด้วย Backbone ทุกวันและมันก็สนุกมากเมื่อคุณเริ่มก้าวกระโดดและเห็นความคล่องแคล่วในเฟรมเวิร์กนี้เติบโตขึ้น :-)

ขอให้สนุกกับการเขียนโค้ด!

แก้ไข: แหล่งข้อมูลที่อาจเป็นประโยชน์:

คำตอบอื่น ๆ ที่คล้ายกันเกี่ยวกับ SO: วิธีสร้าง ID โมเดลด้วย Backbone

ใน REST: http://rest.elkstein.org/ http://www.infoq.com/articles/rest-introduction http://www.recessframework.org/page/towards-restful-php-5-basic- เคล็ดลับ


9
ฉันลงเอยด้วยเรื่องนี้เล็กน้อย ฉันจำได้ว่าตอนที่ฉันเริ่ม Backbone ครั้งแรกและมีคำถามเช่นผู้ถามและฉันก็สนุกกับการเขียนคำตอบ ฉันแน่ใจว่าในความเร่งรีบของฉันฉันได้ทำผิดพลาดบางอย่างหรือพลาด "อา - ฮ่า! แง่มุมถ้าเป็นเช่นนั้นแจ้งให้เราทราบ :-P
jmk2142

6
คำตอบที่น่าเหลือเชื่อที่จะพูดอย่างน้อยที่สุด ... ฉันพยายามเข้าใจทุกสิ่งที่คุณพูดถึง.. สิ่งที่เหลือดูยากไปหน่อยแม้ว่าคุณจะพูดถูก แต่คุณไม่สามารถอธิบายฉันได้อย่างแน่นอน REST ภายในคำถามนี้ ... ฉัน ' จะผ่านสิ่งต่างๆอีกครั้งและยอมรับในบางครั้ง ... ขอบคุณอีกครั้งสำหรับคำตอบโดยละเอียด ...
testndtv

2
เมื่อฉันได้เวลาฉันจะอัปเดตคำตอบของฉันพร้อมกับรายการข้อมูลอ้างอิงที่ดีที่สามารถช่วยคุณในการสืบเสาะ ฉันไม่สามารถมอบดาบไม้ให้คุณเพื่อเผชิญหน้ากับโลกอันตรายที่นั่นได้ แต่ฉันสามารถให้ลิงค์แหล่งข้อมูลของไซต์ที่ช่วยฉันได้ :-)
jmk2142

5
@testndtv ฉันตอบคำถามของคุณหรือไม่? จะมีการชื่นชมเครื่องหมาย√
jmk2142

2
ไม่ต้องสงสัยเลยว่าคุณตอบคำถามเกินคาด ... ผมยอมรับคำตอบแล้ว.. ขอบคุณมากอีกครั้งสำหรับความช่วยเหลือ ..
testndtv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.