Koa.js - RESTful API'ler
Mobil uygulamalar, tek sayfalı uygulamalar oluşturmak, AJAX çağrılarını kullanmak ve istemcilere veri sağlamak için bir API'ye ihtiyacınız olacaktır. Bu API'lerin ve uç noktaların nasıl yapılandırılacağına ve adlandırılacağına dair popüler bir mimari stile denirREST(Representational Transfer State). HTTP 1.1, REST ilkeleri göz önünde bulundurularak tasarlanmıştır. REST tarafından tanıtıldıRoy Fielding 2000 yılında Fielding Dissertations adlı makalesinde.
RESTful URI'ler ve yöntemler, bir isteği işlemek için ihtiyacımız olan neredeyse tüm bilgileri bize sağlar. Aşağıdaki tablo, çeşitli fiillerin nasıl kullanılması gerektiğini ve URI'lerin nasıl adlandırılması gerektiğini özetlemektedir. Sonlara doğru bir film API'si oluşturacağız, şimdi nasıl yapılandırılacağını tartışalım.
Yöntem | URI | Detaylar | Fonksiyon |
---|---|---|---|
ALMAK | / filmler | Güvenli, önbelleğe alınabilir | Tüm filmlerin listesini ve ayrıntılarını alır |
ALMAK | / filmler / 1234 | Güvenli, önbelleğe alınabilir | Film kimliği 1234'ün ayrıntılarını alır |
İLETİ | / filmler | Yok | Sağlanan ayrıntılarla yeni bir film oluşturur. Yanıt, bu yeni oluşturulan kaynak için URI'yi içerir. |
KOYMAK | / filmler / 1234 | Etkisiz | Film kimliği 1234'ü değiştirir (zaten yoksa bir tane oluşturur). Yanıt, bu yeni oluşturulan kaynak için URI'yi içerir. |
SİL | / filmler / 1234 | Etkisiz | Film kimliği 1234, varsa silinmelidir. Yanıt, talebin durumunu içermelidir. |
SİL veya PUT | / filmler | Geçersiz | Geçersiz olmalı. DELETE ve PUT, hangi kaynak üzerinde çalıştıklarını belirtmelidir. |
Şimdi bu API'yi Koa'da oluşturalım. JavaScript ile çalışması kolay olduğu ve birçok başka faydası olduğu için aktarım veri formatımız olarak JSON kullanacağız. İndex.js dosyanızı aşağıdakilerle değiştirin -
INDEX.JS
var koa = require('koa');
var router = require('koa-router');
var bodyParser = require('koa-body');
var app = koa();
//Set up body parsing middleware
app.use(bodyParser({
formidable:{uploadDir: './uploads'},
multipart: true,
urlencoded: true
}));
//Require the Router we defined in movies.js
var movies = require('./movies.js');
//Use the Router on the sub route /movies
app.use(movies.routes());
app.listen(3000);
Artık uygulamamızı kurduğumuza göre, API'yi oluşturmaya odaklanalım. Önce movies.js dosyasını ayarlayın. Filmleri depolamak için bir veritabanı kullanmıyoruz, ancak bunları hafızada saklıyoruz, bu nedenle sunucu her yeniden başlatıldığında bizim tarafımızdan eklenen filmler kaybolacak. Bu, bir veritabanı veya dosya kullanılarak kolayca taklit edilebilir (düğüm fs modülü kullanılarak).
Koa-router'ı içe aktarın, bir Router oluşturun ve module.exports'u kullanarak bunu dışa aktarın.
var Router = require('koa-router');
var router = Router({
prefix: '/movies'
}); //Prefixed all routes with /movies
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 Rotaları
Tüm filmleri almak için GET rotasını tanımlayın.
router.get('/', sendMovies);
function *sendMovies(next){
this.body = movies;
yield next;
}
Bu kadar. Bunun düzgün çalışıp çalışmadığını test etmek için uygulamanızı çalıştırın, ardından terminalinizi açın ve şunu girin -
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies
Aşağıdaki yanıtı alacaksınız -
[{"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}]
Tüm filmleri almak için bir rotamız var. Şimdi kimliğine göre belirli bir filmi almak için bir rota oluşturalım.
router.get('/:id([0-9]{3,})', sendMovieWithId);
function *sendMovieWithId(next){
var ctx = this;
var currMovie = movies.filter(function(movie){
if(movie.id == ctx.params.id){
return true;
}
});
if(currMovie.length == 1){
this.body = currMovie[0];
} else {
this.response.status = 404;//Set status to 404 as movie was not found
this.body = {message: "Not Found"};
}
yield next;
}
Bu bize verdiğimiz kimliğe göre filmleri alacaktır. Bunu test etmek için, terminalinizde aşağıdaki komutu kullanın.
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET localhost:3000/movies/101
Yanıtı şu şekilde alacaksınız -
{"id":101,"name":"Fight Club","year":1999,"rating":8.1}
Geçersiz bir rotayı ziyaret ederseniz, bir GET hatası üretirken, mevcut olmayan bir kimliğe sahip geçerli bir rotayı ziyaret ederseniz, bir 404 hatası oluşturur.
GET rotalarıyla işimiz bitti. Şimdi POST rotasına geçelim.
POST Rotası
POST ile gönderilen verileri işlemek için aşağıdaki yolu kullanın.
router.post('/', addNewMovie);
function *addNewMovie(next){
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
var newId = movies[movies.length-1].id+1;
movies.push({
id: newId,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + newId};
}
yield next;
}
Bu, yeni bir film oluşturacak ve bunu filmler değişkeninde saklayacaktır. Bu rotayı test etmek için terminalinize şunu girin -
curl -X POST --data "name = Toy%20story&year = 1995&rating = 8.5"
https://localhost:3000/movies
Aşağıdaki yanıtı alacaksınız -
{"message":"New movie created.","location":"/movies/105"}
Bunun movies nesnesine eklenip eklenmediğini test etmek için / movies / 105 için alma isteğini yeniden çalıştırın. Aşağıdaki yanıtı alacaksınız -
{"id":105,"name":"Toy story","year":"1995","rating":"8.5"}
PUT ve DELETE rotalarını oluşturmaya devam edelim.
PUT Rotası
PUT rotası, POST rotasıyla neredeyse tamamen aynıdır. Güncellenecek / oluşturulacak nesnenin kimliğini belirleyeceğiz. Rotayı aşağıdaki şekilde oluşturun -
router.put('/:id', updateMovieWithId);
function *updateMovieWithId(next){
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
!this.params.id.toString().match(/^[0-9]{3,}$/g)){
this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
//Gets us the index of movie with given id.
var updateIndex = movies.map(function(movie){
return movie.id;
}).indexOf(parseInt(this.params.id));
if(updateIndex === -1){
//Movie not found, create new movies.push({
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + this.params.id};
} else {
//Update existing movie
movies[updateIndex] = {
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
};
this.body = {message: "Movie id " + this.params.id + " updated.", location: "/movies/" + this.params.id};
}
}
}
Bu rota yukarıdaki tabloda belirttiğimiz işlevi yerine getirecektir. Varsa, nesneyi yeni ayrıntılarla günceller. Mevcut değilse, yeni bir nesne oluşturacaktır. Bu rotayı test etmek için aşağıdaki curl komutunu kullanın. Bu, mevcut bir filmi güncelleyecektir. Yeni bir Film oluşturmak için kimliği mevcut olmayan bir kimlik ile değiştirmeniz yeterlidir.
curl -X PUT --data "name = Toy%20story&year = 1995&rating = 8.5"
https://localhost:3000/movies/101
Tepki
{"message":"Movie id 101 updated.","location":"/movies/101"}
Rotayı SİL
Bir silme yolu oluşturmak için aşağıdaki kodu kullanın.
router.delete('/:id', deleteMovieWithId);
function *deleteMovieWithId(next){
var removeIndex = movies.map(function(movie){
return movie.id;
}).indexOf(this.params.id); //Gets us the index of movie with given id.
if(removeIndex === -1){
this.body = {message: "Not found"};
} else {
movies.splice(removeIndex, 1);
this.body = {message: "Movie id " + this.params.id + " removed."};
}
}
Rotayı diğerleri için yaptığımız gibi test edin. Başarılı bir silme işleminde (örneğin id 105), elde edersiniz -
{message: "Movie id 105 removed."}
Son olarak, movies.js dosyamız şuna benzer:
var Router = require('koa-router');
var router = Router({
prefix: '/movies'
}); //Prefixed all routes with /movies
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
router.get('/', sendMovies);
router.get('/:id([0-9]{3,})', sendMovieWithId);
router.post('/', addNewMovie);
router.put('/:id', updateMovieWithId);
router.delete('/:id', deleteMovieWithId);
function *deleteMovieWithId(next){
var removeIndex = movies.map(function(movie){
return movie.id;
}).indexOf(this.params.id); //Gets us the index of movie with given id.
if(removeIndex === -1){
this.body = {message: "Not found"};
} else {
movies.splice(removeIndex, 1);
this.body = {message: "Movie id " + this.params.id + " removed."};
}
}
function *updateMovieWithId(next) {
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g) ||
!this.params.id.toString().match(/^[0-9]{3,}$/g)){
this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
//Gets us the index of movie with given id.
var updateIndex = movies.map(function(movie){
return movie.id;
}).indexOf(parseInt(this.params.id));
if(updateIndex === -1){
//Movie not found, create new
movies.push({
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + this.params.id};
} else {
//Update existing movie
movies[updateIndex] = {
id: this.params.id,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
};
this.body = {message: "Movie id " + this.params.id + " updated.",
location: "/movies/" + this.params.id};
}
}
}
function *addNewMovie(next){
//Check if all fields are provided and are valid:
if(!this.request.body.name ||
!this.request.body.year.toString().match(/^[0-9]{4}$/g) ||
!this.request.body.rating.toString().match(/^[0-9]\.[0-9]$/g)){
this.response.status = 400;
this.body = {message: "Bad Request"};
} else {
var newId = movies[movies.length-1].id+1;
movies.push({
id: newId,
name: this.request.body.name,
year: this.request.body.year,
rating: this.request.body.rating
});
this.body = {message: "New movie created.", location: "/movies/" + newId};
}
yield next;
}
function *sendMovies(next){
this.body = movies;
yield next;
}
function *sendMovieWithId(next){
var ctx = this
var currMovie = movies.filter(function(movie){
if(movie.id == ctx.params.id){
return true;
}
});
if(currMovie.length == 1){
this.body = currMovie[0];
} else {
this.response.status = 404;//Set status to 404 as movie was not found
this.body = {message: "Not Found"};
}
yield next;
}
module.exports = router;
Bu, REST API'mizi tamamlar. Artık bu basit mimari stili ve Koa'yı kullanarak çok daha karmaşık uygulamalar oluşturabilirsiniz.