ExpressJS - RESTFul API
จำเป็นต้องใช้ API เสมอในการสร้างแอปพลิเคชันมือถือแอปพลิเคชันหน้าเดียวใช้การโทร AJAX และให้ข้อมูลแก่ลูกค้า รูปแบบสถาปัตยกรรมที่เป็นที่นิยมในการจัดโครงสร้างและตั้งชื่อ API เหล่านี้และจุดสิ้นสุดเรียกว่าREST(Representational Transfer State). HTTP 1.1ได้รับการออกแบบโดยคำนึงถึงหลักการ REST REST ได้รับการแนะนำโดยRoy Fielding ในปี 2000 ใน Paper Fielding Dissertations
URI และวิธีการ RESTful ให้ข้อมูลเกือบทั้งหมดที่เราต้องการในการดำเนินการตามคำขอ ตารางด้านล่างสรุปว่าควรใช้กริยาต่างๆอย่างไรและควรตั้งชื่อ URI อย่างไร เราจะสร้างภาพยนตร์ API ในตอนท้าย ตอนนี้ให้เราคุยกันว่าจะมีโครงสร้างอย่างไร
วิธี | URI | รายละเอียด | ฟังก์ชัน |
---|---|---|---|
รับ | /ภาพยนตร์ | ปลอดภัยสามารถเข้าถึงได้ | รับรายชื่อภาพยนตร์ทั้งหมดและรายละเอียด |
รับ | / movies / 1234 | ปลอดภัยสามารถเข้าถึงได้ | รับรายละเอียดของ Movie id 1234 |
โพสต์ | /ภาพยนตร์ | ไม่มี | สร้างภาพยนตร์ใหม่พร้อมรายละเอียดที่ให้ไว้ การตอบกลับมี URI สำหรับทรัพยากรที่สร้างขึ้นใหม่นี้ |
วาง | / movies / 1234 | Idempotent | แก้ไขรหัสภาพยนตร์ 1234 (สร้างใหม่หากยังไม่มี) การตอบกลับมี URI สำหรับทรัพยากรที่สร้างขึ้นใหม่นี้ |
ลบ | / movies / 1234 | Idempotent | ควรลบ Movie id 1234 หากมีอยู่ การตอบกลับควรมีสถานะของคำขอ |
ลบหรือวาง | /ภาพยนตร์ | ไม่ถูกต้อง | ควรจะไม่ถูกต้อง DELETE และ PUT ควรระบุว่าทรัพยากรใดกำลังทำงานอยู่ |
ให้เราสร้าง API นี้ใน Express เราจะใช้ JSON เป็นรูปแบบข้อมูลการขนส่งของเราเนื่องจากใช้งานง่ายใน JavaScript และมีประโยชน์อื่น ๆ แทนที่ไฟล์index.js ไฟล์ด้วยไฟล์ movies.js ไฟล์ในโปรแกรมต่อไปนี้
index.js
var express = require('express');
var bodyParser = require('body-parser');
var multer = require('multer');
var upload = multer();
var app = express();
app.use(cookieParser());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(upload.array());
//Require the Router we defined in movies.js
var movies = require('./movies.js');
//Use the Router on the sub route /movies
app.use('/movies', movies);
app.listen(3000);
ตอนนี้เราได้ตั้งค่าแอปพลิเคชันแล้วให้เรามีสมาธิในการสร้าง API
เริ่มต้นด้วยการตั้งค่าไฟล์ movies.js เราไม่ได้ใช้ฐานข้อมูลในการจัดเก็บภาพยนตร์ แต่กำลังจัดเก็บไว้ในหน่วยความจำ ดังนั้นทุกครั้งที่เซิร์ฟเวอร์รีสตาร์ทภาพยนตร์ที่เราเพิ่มเข้ามาจะหายไป สิ่งนี้สามารถเลียนแบบได้อย่างง่ายดายโดยใช้ฐานข้อมูลหรือไฟล์ (โดยใช้โมดูลโหนด fs)
เมื่อคุณนำเข้า Express แล้วให้สร้างเราเตอร์และส่งออกโดยใช้module.exports -
var express = require('express');
var router = express.Router();
var movies = [
{id: 101, name: "Fight Club", year: 1999, rating: 8.1},
{id: 102, name: "Inception", year: 2010, rating: 8.7},
{id: 103, name: "The Dark Knight", year: 2008, rating: 9},
{id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];
//Routes will go here
module.exports = router;
รับเส้นทาง
ให้เรากำหนดเส้นทาง GET เพื่อรับภาพยนตร์ทั้งหมด -
router.get('/', function(req, res){
res.json(movies);
});
หากต้องการทดสอบว่าใช้งานได้ดีหรือไม่ให้เรียกใช้แอปของคุณจากนั้นเปิดเทอร์มินัลแล้วป้อน -
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET
localhost:3000/movies
คำตอบต่อไปนี้จะปรากฏขึ้น -
[{"id":101,"name":"Fight Club","year":1999,"rating":8.1},
{"id":102,"name":"Inception","year":2010,"rating":8.7},
{"id":103,"name":"The Dark Knight","year":2008,"rating":9},
{"id":104,"name":"12 Angry Men","year":1957,"rating":8.9}]
เรามีเส้นทางในการรับชมภาพยนตร์ทั้งหมด ตอนนี้ให้เราสร้างเส้นทางเพื่อรับภาพยนตร์เฉพาะโดยใช้รหัส
router.get('/:id([0-9]{3,})', function(req, res){
var currMovie = movies.filter(function(movie){
if(movie.id == req.params.id){
return true;
}
});
if(currMovie.length == 1){
res.json(currMovie[0])
} else {
res.status(404);//Set status to 404 as movie was not found
res.json({message: "Not Found"});
}
});
สิ่งนี้จะทำให้เราได้รับภาพยนตร์ตาม id ที่เราให้ไว้ ในการตรวจสอบผลลัพธ์ให้ใช้คำสั่งต่อไปนี้ในเทอร์มินัลของคุณ -
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET
localhost:3000/movies/101
คุณจะได้รับคำตอบดังต่อไปนี้ -
{"id":101,"name":"Fight Club","year":1999,"rating":8.1}
หากคุณไปที่เส้นทางที่ไม่ถูกต้องมันจะสร้างไฟล์ cannot GET error ในขณะที่หากคุณไปยังเส้นทางที่ถูกต้องโดยมีรหัสที่ไม่มีอยู่จะทำให้เกิดข้อผิดพลาด 404
เราทำเส้นทาง GET เสร็จแล้วให้เราไปที่ POST เส้นทาง.
เส้นทาง POST
ใช้เส้นทางต่อไปนี้เพื่อจัดการไฟล์ POSTed ข้อมูล -
router.post('/', function(req, res){
//Check if all fields are provided and are valid:
if(!req.body.name ||
!req.body.year.toString().match(/^[0-9]{4}$/g) ||
!req.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
res.status(400);
res.json({message: "Bad Request"});
} else {
var newId = movies[movies.length-1].id+1;
movies.push({
id: newId,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
});
res.json({message: "New movie created.", location: "/movies/" + newId});
}
});
การดำเนินการนี้จะสร้างภาพยนตร์ใหม่และจัดเก็บไว้ในตัวแปรภาพยนตร์ ในการตรวจสอบเส้นทางนี้ให้ป้อนรหัสต่อไปนี้ในอาคารผู้โดยสารของคุณ -
curl -X POST --data "name = Toy%20story&year = 1995&rating = 8.5" http://localhost:3000/movies
คำตอบต่อไปนี้จะปรากฏขึ้น -
{"message":"New movie created.","location":"/movies/105"}
หากต้องการทดสอบว่าสิ่งนี้ถูกเพิ่มลงในวัตถุภาพยนตร์หรือไม่ให้เรียกใช้คำขอรับ /movies/105อีกครั้ง. คำตอบต่อไปนี้จะปรากฏขึ้น -
{"id":105,"name":"Toy story","year":"1995","rating":"8.5"}
ให้เราไปสร้างเส้นทาง PUT และ DELETE
PUT เส้นทาง
เส้นทาง PUT เกือบจะเหมือนกับเส้นทาง POST เราจะระบุรหัสสำหรับวัตถุที่จะอัปเดต / สร้างขึ้น สร้างเส้นทางด้วยวิธีต่อไปนี้
router.put('/:id', function(req, res){
//Check if all fields are provided and are valid:
if(!req.body.name ||
!req.body.year.toString().match(/^[0-9]{4}$/g) ||
!req.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
!req.params.id.toString().match(/^[0-9]{3,}$/g)){
res.status(400);
res.json({message: "Bad Request"});
} else {
//Gets us the index of movie with given id.
var updateIndex = movies.map(function(movie){
return movie.id;
}).indexOf(parseInt(req.params.id));
if(updateIndex === -1){
//Movie not found, create new
movies.push({
id: req.params.id,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
});
res.json({message: "New movie created.", location: "/movies/" + req.params.id});
} else {
//Update existing movie
movies[updateIndex] = {
id: req.params.id,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
};
res.json({message: "Movie id " + req.params.id + " updated.",
location: "/movies/" + req.params.id});
}
}
});
เส้นทางนี้จะทำหน้าที่ตามที่ระบุไว้ในตารางด้านบน มันจะอัปเดตออบเจ็กต์ด้วยรายละเอียดใหม่หากมีอยู่ ถ้าไม่มีก็จะสร้างวัตถุใหม่ ในการตรวจสอบเส้นทางให้ใช้คำสั่ง curl ต่อไปนี้ การดำเนินการนี้จะอัปเดตภาพยนตร์ที่มีอยู่ หากต้องการสร้างภาพยนตร์ใหม่เพียงแค่เปลี่ยนรหัสเป็นรหัสที่ไม่มีอยู่
curl -X PUT --data "name = Toy%20story&year = 1995&rating = 8.5"
http://localhost:3000/movies/101
Response
{"message":"Movie id 101 updated.","location":"/movies/101"}
ลบเส้นทาง
ใช้รหัสต่อไปนี้เพื่อสร้างเส้นทางการลบ -
router.delete('/:id', function(req, res){
var removeIndex = movies.map(function(movie){
return movie.id;
}).indexOf(req.params.id); //Gets us the index of movie with given id.
if(removeIndex === -1){
res.json({message: "Not found"});
} else {
movies.splice(removeIndex, 1);
res.send({message: "Movie id " + req.params.id + " removed."});
}
});
ตรวจสอบเส้นทางในลักษณะเดียวกับที่เราตรวจสอบเส้นทางอื่น ๆ เมื่อการลบสำเร็จ (เช่น id 105) คุณจะได้ผลลัพธ์ต่อไปนี้ -
{message: "Movie id 105 removed."}
ในที่สุด movies.js ไฟล์จะมีลักษณะดังต่อไปนี้
var express = require('express');
var router = express.Router();
var movies = [
{id: 101, name: "Fight Club", year: 1999, rating: 8.1},
{id: 102, name: "Inception", year: 2010, rating: 8.7},
{id: 103, name: "The Dark Knight", year: 2008, rating: 9},
{id: 104, name: "12 Angry Men", year: 1957, rating: 8.9}
];
router.get('/:id([0-9]{3,})', function(req, res){
var currMovie = movies.filter(function(movie){
if(movie.id == req.params.id){
return true;
}
});
if(currMovie.length == 1){
res.json(currMovie[0])
} else {
res.status(404); //Set status to 404 as movie was not found
res.json({message: "Not Found"});
}
});
router.post('/', function(req, res){
//Check if all fields are provided and are valid:
if(!req.body.name ||
!req.body.year.toString().match(/^[0-9]{4}$/g) ||
!req.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
res.status(400);
res.json({message: "Bad Request"});
} else {
var newId = movies[movies.length-1].id+1;
movies.push({
id: newId,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
});
res.json({message: "New movie created.", location: "/movies/" + newId});
}
});
router.put('/:id', function(req, res) {
//Check if all fields are provided and are valid:
if(!req.body.name ||
!req.body.year.toString().match(/^[0-9]{4}$/g) ||
!req.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
!req.params.id.toString().match(/^[0-9]{3,}$/g)){
res.status(400);
res.json({message: "Bad Request"});
} else {
//Gets us the index of movie with given id.
var updateIndex = movies.map(function(movie){
return movie.id;
}).indexOf(parseInt(req.params.id));
if(updateIndex === -1){
//Movie not found, create new
movies.push({
id: req.params.id,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
});
res.json({
message: "New movie created.", location: "/movies/" + req.params.id});
} else {
//Update existing movie
movies[updateIndex] = {
id: req.params.id,
name: req.body.name,
year: req.body.year,
rating: req.body.rating
};
res.json({message: "Movie id " + req.params.id + " updated.",
location: "/movies/" + req.params.id});
}
}
});
router.delete('/:id', function(req, res){
var removeIndex = movies.map(function(movie){
return movie.id;
}).indexOf(req.params.id); //Gets us the index of movie with given id.
if(removeIndex === -1){
res.json({message: "Not found"});
} else {
movies.splice(removeIndex, 1);
res.send({message: "Movie id " + req.params.id + " removed."});
}
});
module.exports = router;
เสร็จสมบูรณ์ REST API ของเรา ตอนนี้คุณสามารถสร้างแอปพลิเคชันที่ซับซ้อนมากขึ้นโดยใช้รูปแบบสถาปัตยกรรมที่เรียบง่ายและ Express