Node.js ile Uygulama Geliştirme – 4 : REST Mimarisi ve RESTful Servisler Geliştirme [Express Framework ]

Express Web Framework

Seriye devam ederken express.js e, eko-sistemine ve genel olarak çalışma mantığına bakmayi ihmal etmeyelim. Express gayet sade ve kullanımı kolay bir framework, bu yüzden çok ciddi bir kullanım oranına sahip node.js dünyasında. Daha önce belirttiğim gibi, bir çok diğer node.js framework ü de Express üzerine inşa edilmiş durumda.

Express framework ün çalışma mantığına bakacak olursak, aşağıdaki parçalardan oluşan minimal bir yapıyı görebiliriz;

  1. express nesnesi.
  2. Routing – Rota yönetimi
  3.  Middleware

Bu 3 parça ya video da daha detayli bakmaya calistim. Söz uçar yazı kalır hesabı bir de genel olarak bu yazı ile bakarak devam edelim.

express nesnesi – Instance of Express Class

Express i npm i ile indirip uygulamamıza dahil ediş sürecinden sonra, freamework ün örneğini tutan bir sınıf oluşturup bu sınıfı kullanarak, başta ayarlar ve rota tanımlarımız olmak üzere hemen hemen her şeyi bu oluşturduğumuz express nesnesi üzerinden yapmaktayız. Diğer framework lere göre daha sade ve kolay bir yapı sağlayan bu yöntem, uygulamanın modüler bir şekilde de tasarlanmasına imkan vermekte.

import express from "express"; // express paketini dahil ediyoruz
const app = express(); // express nesnemiz.

Express sınıfından bir örnek oluşturarak başlıyoruz. Artık app isimli değişkenimizi kullanarak express framework ün bize sağladığı tüm altyapıyı kullanabiliriz. express nesnemizin bize sunduğu ilk kolaylık .get() ve .set() metodları.  Bu iki metodun iki farklı kullanımı söz konusu ilk kullanım şekilleri ;

.get() ve .set()

1- Uygulama genelinde bazi konfigürasyonlari yapabilmemize yada sornada bu ayarlarla ulaşabilmemize imkan vermekteler. Bu konfigürasyonların bir kısmı express içinde dahili olarak gelen ayarlar.

2- Dahili konfigürasyonların dışında, kendi tanımlaycağımız değerler içinde kullanabilmekteyiz. iki kullanımada aşağıda bakarak devam edelim.

Dahili konfigürasyonlar

app.set('env', 'development'); // express geliştirme ortamında çalışacak
app.get('env'); // "development"
app.set("json spaces", "5") // Json formatını ayarladık.

Yukarıdaki gibi bir çok dahili konfigürasyonu kullanarak uygulamamızın genel ayarlarını güncelleyebilir(.set()) yada hangi ayarları kullandığımızı ( .get() ) öğrenebiliriz. Dahili konfigürasyonların listesine buradan bakabilirsiniz. 

Kendi tanımlamalarımızıda aynı şekilde .get() ve .set() ile kullanabilmekteyiz.

app.set('title', 'My Site');
app.get('title'); // "My Site"

.get() metodunun bir başka kullanım şekli daha var yazının devamında onada bakacağız.

.use() Metodu

Express için de önemli bir yer tutan .use() metodu, genel olarak uygulamamızın tamamı yada bir kısmı için çalıştırmak istediğimiz middleware ler için kullanmaktayız. middleware kavramını hiç duymadıysanız, genel bir tanım olarak şöyle ifade edebiliriz “bir middleware için, uygulamamıza gelen (http) isteklerinden önce çalışan fonksiyon” tanımını kullanabiliriz. Yazının devamında bu kısıma tekrar döneceğiz. Ayrıca video da da daha rahat anlaşılır bir şekilde pratikdeki karşılıklarına bakmaya çalıştım.

Örneğin uygulamamızda “/admin” yoluna gelen her istekden önce bazı işlemler yapmak istersek şöyle bir middleware tanımlayabiliriz.

app.use('/admin', function(req, res, next) {
  // GET 'http://www.example.com/admin/new'
  console.log(req.originalUrl); // '/admin/new'
  console.log(req.baseUrl); // '/admin'
  console.log(req.path); // '/new'
  next();
});

Eğer her hangi bir yol belirtmezisek , sadece /admin yoluna gelen istekler değil , sunucumuza gelen tüm istekler için çalışacak bir middleware tanımlamış oluyoruz;

// this middleware will be executed for every request to the app
app.use(function (req, res, next) {
  console.log('Time: %d', Date.now());
  next();
});

Yukaridaki örneklerde geçen ” req, res, next ” gibi terimlere daha yakından bakacağız. Şimdilik, .use() metodunun, uygulamamıza “middleware” bağlama için kullanabileceğimiz temel metod olduğunu söyleyerek devam edelim.

.static() Metodu

Genelde web dünyası içinde “static assets”  diye tabir edilen, fiziki/statik dosyalarımızı istemciye göndermek ve yönetmek için bazı ayarlari yapabileceğimiz yardımcı bir method. statik dosyalardan kastımız ise her türlü “css, html,js” vb. dinamik olarak oluşturulmayan dosyalar.

Üç aşağı beş yukarı uygulamamızı konfigüre ederken kullanacağımız ana metodlar bunlar diyebiliriz. Bir kaç başka metod yada alternatif olsada çoğu zaman yukarıda bahsettiğimiz metodlar ve genel olarak express app nesnesi bir çok durum için yeterli olacaktır. Şimdi , express içinde routing e bakarak devam edelim.

Express Framework ve Routing / Restfull Rotalar.

Express routing alt yapısı için 2 farklı yöntem sunmakta.

  1. Kısa yol metodları
  2. Router sınıfı

Kısa yol metodları

Restfull mimari içinde sıklıkla kullandığımız “http verbs” olarak da bilinen http istek türlerimizi karşılayan metodlar diyebiliriz. Ben burada en çok kullanılan 4 tanesine ve birde özel all() metoduna değineceğim çoğu durumda zaten bu 5 i bütün ihtiyaçlarımıza yetecektir. Diğer kullanılabilir metodlar için buraya bakabilirsiniz. (app.METHOD(path, callback [, callback …]) kısmı altında lıstelenmişler)

4 kısa yol metodumuz tahmin edebileceğiniz gibi şu vatandaşlar;

.get()
.post()
.delete()
.put()

Sadece  .get() metodu için bir hatırlatma yapmak lazım, yazının başında bu metodu farklı bir şekilde de kullanmıştık.(.set() ve .get() ) Burada bu metoda tek bir parametre vererek kullanırsak, routing metodu olarak değil konfigürasyon metodu olarak çalışmakta. Eğer 1 den fazla para metre alırsa bir routing metodu olarak çalışacak. Şimdi aşağıdaki 4 örneğe bakarak devam edelim;

“/urunler” şeklinde bir rota için GET  requestleri/isteklerini karşılayacak bir rotayı şu şekilde yazabilmekteyiz

app.get('/urunler', function (req, res) {
  res.send('GET request alındı');
});
// /urunler yoluna yapılan GET Requestleri/İstekleri karşılar.

aynı şekilde app.[HTTP_VERB] şeklinde dilediğimiz isteği dilediğimiz path/yol için karşılayabilmekteyiz. Örnek bir POST request/isteği ne bakalım;

app.post('/urunler', function (req, res) {
  res.send('POST request alındı');
});
// /urunler yoluna yapılan POST Requestleri/İstekleri karşılar.

aynı şekilde tahmin edebileceğiniz gibi, app.delete(“/urunler”) yada app.put(“/urunler”) gibi bir tanımlamada sırasıyla “/urunler” adresine gelen delete ve put request/isteklerini karşılamış olacağız.

diğer bir kısayol metodumuz .all() ise isimlendirmesinden de anlaşılacağı gibi, isteğin türüne bakmadan(GET,PUT,POST vs.) belirli bir yol için tüm istekleri karşılamak için kullanılmakta.

app.all('/api/*', function (req,res) {
    // /api ve tum alt varyasyonlari icin gecerli rotamiz
    // /api/users yada /api/users/:userId gibi
});

Kısa yol metdolarımızın kullanımları gayet basit, hedeflediğimiz http verb (get,post put,delete) e ilk parametre olarak path/yol ikinci parametre olarakda gelen isteği işleyecek fonksiyon yada eğer MVC gibi bir yapı kullanıyorsanız, ilgili control ü sağlamanız yeterli olacaktır. Son kısa yol metodumuz ise .route().

.route()

app.route('/urunler')
.all(function(req, res, next) {
  // runs for all HTTP verbs first
  // think of it as route specific middleware!
})
.get(function(req, res, next) {
  res.json(...);
})
.post(function(req, res, next) {
  // maybe add a new event...
});

.route() metodu ile belirlediğimiz  yol için tek bir seferde tüm http verb lerini birbirine  “Chain / ekleme” yaparak rotalarımızı tanımlayabilmekteyiz.

Diğer alternatif olan Router nesnesine geçmeden önce her iki yapı ve ayrıca tüm middleware ler için geçerli olan bir diğer konuya bakalım.

Request Response ve Next / Gelen İstek, İsteğe Cevap ve İsteği bir sonraki noktaya aktarım 

Yukarıdaki örneklerde kullandığımız şu yapıyı hatırlayalım;

app.get('/urunler', function(req, res, next)

tanımladığımız rota ve bu rotaya geçtiğimiz fonksiyona parametre olarak verdiğimiz 3 nesnemiz mevcut bu nesneler sırasıyla

  1. Request / İstek
  2. Response / Cevap
  3. Next / Akış kontrol nesnesi.

yukarıda req , res ve next olarak kısa isimledirsekte, express.js bizim için tüm rota tanımlamalarında ve middleware lerde kullanabilmemiz için bu sıraya sadık kalarak 3 nesneyi bize sağlamakta. Yani, isimlendirme yi nasıl yaparsanız yapın önemli olan sıralamanız olacak. Örneğin tamamen türkçe olarak şu şekilde bir kullanımda gecerlidir.

app.get('/urunler', function(istek, cevap, sonraki)

yukarıdaki örnekte, istek nesnemize Request nesnesi, cevap nesnemize de Response nesnesi atanacaktır. Peki genel olarak nedir bu Request ve Response nesnelerimiz.

Request :

İstemciden gelen tüm bilgileri taşıyan ana nesnemiz. Bu nesne sayesinde kullanıcıdan gelen verileri, istemci bilgisi vs. dahil bir çok veriye ulaşım imkanımız olmakta.

Response:

İstemciye göndereceğimiz cevabı temsil eden nesnemiz. .send() , .status() vb. bir çok kısayol metodu da sunmakta.

Next:

Gelen isteği belirli bir işlemden geçirdikten sonra yada bazı kontrollere tabi tuttuktan sonra, “isteği” uygulama akışı içinde bir sonraki noktaya yönlendirmek için kullanabileceğimiz metod. Burada dikkat edilmesi gereken bir detay, web isteğinin “forwarding/yönlendirilme” yapılmadığı sadece uygulamız içinde bir sonraki kontrole aktarıldığıdır.

Bu 3 nesneyede video da değindiğimiz için ve sonraki süreçte bol bol kullanacağımız için burada kısa tutalım.

Router Nesnesi.

Yukarıda, kısa yol metdolarına değindik, bu kısa yol metodlarına bir alternatif olarak express bize bir de Router Nesnesini sunmakta. Router nesnesi daha düzenli bir yazım şekline sahip ve uygulamamızı daha modüler bir halde yazmamıza yardımcı olmakta.  Router nesnesi ile, aslında uygulamızı kendi için küçük parçalara ayrımış oluyoruz diyebiliriz. Kullanımı şu şekilde olacaktır;

Öncelikle express in sağladığı Router sınıfının bir örneği oluşuturarak başlıyoruz.

var router = express.Router([options]);

router nesenimizi artık aşağıdaki gibi kullanabiliriz;

router.get('/mezun', function(req, res, next) {
 // /ogrenciler/mezun yolu - GET });
router.get('/aktif', function(req, res, next) {
 // .. /ogrenciler/aktif yolu - GET }); 
app.use('/ogrenciler', router)


burada dikkat etmemiz gereken en önemli nokta; app.use(‘/ogrenciler’, router)  tanımı ile, uygulamamızın “/ogrenciler” yolu için yapılacak bütün istekleri artık bir alt rota katmanına alıyoruz. Video daki örnekte daha belirgin bir şekilde uygulamızın rota tanımlalarını Router nesnesi ile nasıl organize edebildiğimize baktık.

Url Parametrelerin tanımlanması veya Request/İstekle gelen gövdedeki verinin(body) işlenmesi / elde edilmesi

Ne tür bir uygulama geliştirirsek geliştirelim, kullanıcılarımızdan bazı veriler almak zorundayız. Web / API sunucuları gibi http üzerinden çalışacak uygulamalarımız için aşağıdaki iki durum söz konusu olacaktır.

  1. URL parametreleri
  2. BODY/ Govde ile gelen veriler

URL parametreleri

Express framework ile http isteklerimiz üzerinden gelen iki türlü parametremiz olacaktır.

  1. Query String
    1. /urunler?siralama=artan&depo=2
  2. Named Paramters – isimlendirilmis parametreler
    1. /urunler/:urunNo

query string olarak (url adresimize ? isaretin ardindan ekledgimiz anahtar/deger ikilileri) gelen verileri expressin rotalarımız ve middleware lerimiz için sağladığı Request nesnesi üzerinden şu şekilde ulaşabiliriz;

Query String

// urunler?siralama=artan&depo=2
app.get('/urunler/', function(req, res) {
    var siralama = req.query.siralama
    var depo = req.query.depo
    console.log("sira : ",siralama, " , depo : " , depo);
    res.send(urunler);
});

Named / İsimlendirilmiş Parametreler

// urunler/123
app.get('/urunler/:urunId', function(req, res) {
    var urunId = req.params.urunId
    console.log("urunId: ",urunId);
    res.send(urun);
});

Request nesnesinin bize sunduğu query ve params ile url ile gelen her türlü veriye ve değişkene erişim imkanımız olmakta.

BODY/ Govde ile gelen veriler

Kullanıcının bir  POST request ile sunucuya (BODY/Gövde içinde) veri gönderdiği durumlarda ise yine Request nesnemizin yardımı ile bu veriye ulaşabilmekteyiz;

req.body

app.post('/profile',  function (req, res, next) {
  console.log(req.body);
  res.json(req.body);
});

Middlewares

Node.js ve Express açısından baktığımızda, middleware kavramı için “gelen her türlü isteğe , isteğin gerçekten işleneceği kısımdan önce erişimi olan ve istek üzerinde filitrelemeler, kontroller vb işlemleri yapmamıza imkan veren ön-fonksiyonlar” diyebiliriz.

Aslında yukarıda, rotalarımız için kullandığımız bütün fonksiyonlar “teknik olarak” bir middleware diyebiliriz. Pratikde ise “gelen isteğin işlenme noktası olanlara değil, filitreleme, istek üzerinde modifikasyonlar veya ön kontroller yapan fonksiyonlara ” Middleware diyoruz.

Yani teknik olarak bir midleware ile, bir rotaya geçtiğimiz fonksiyon aslında aynı şey sadece kullanım amaçları yüzünden farklı isimlendirilerek, sanal bir izolasyon yada gruplama yapmış olma durumu var. Şimdi şu örneğe bakalım;

app.use('/urunler/*',function (req,res,next) {
    // /urunler ve bu url in tum varyasyonlarina yapilan istekler
    //icin gecerli middleware
    if(req.query.access_key){
        next()
    }else {
        // istegi geri cevir
        return res.status(401).send('access key saglanmadi!')
    }
})
app.get('/urunler', function (req, res) {
    res.status(200).send({urun:db.Urun.findAll()})
})
app.get('/urunler/:id', function (req, res) {
    res.status(200).send({urun:db.Urun.find(req.params.id)})
})

Yukarıdaki, örneğe bakacak olursak, ilk tanımlamamız (“/urunler/*”) bir middleware ve yaptığı iş belirli şartlara uyan tüm istekler için (/urunler yoluna ve tüm alt varyasyonlarına) bir ön kontrol yapmakta. Bizim örneğimizde gelen istek eğer bir access_key değeri taşımıyorsa isteği sonlandırmakla görevli.

return res.status(401).send(‘access key saglanmadi!’)

Eğer bir access_key sağlandıysa isteğin yoluna devam etmesine izin vermekte.

next()

Böylece, uygulamın içinde bir çok yerde tek tek bu kontrolü yapmaktansa, isteğin geldi ilk noktada bir kere yapıp kısa yoldan bu ihtiyacı gidermiş oluyoruz.

Middleware kavramı için bir başka önemli hatırlatmada, Başkalarının yazdığı küçük yada kompleks bir çok middleware i bir yönüyle plug-in/eklenti gibi uygulamanıza dahil edebilirsiniz. Bir çok farklı ihtiyaç için kullanabileceğimiz çok sayıda middleware i npm  üzerinden veya eski usul kopyla / yapıştır ile uuygulamamıza dahil edebilmekteyiz.

Express bizim için sade bir alt yapı sunuyor dedik, aşağıdaki 3 parçayı tekrar edecek olursak, uygulamamız bu 3 lü üzerine inşa edilmiş olacak.

  1. express nesnesi.
  2. Routing – Rota yönetimi
  3.  Middleware

Videoda yazıdaki konuların pratik kullanımlarına değinmeye çalıştım. Bir sonraki yazıda uygulamamızı yazmaya başlayabiliriz.

Kolay Gelsin.

[fvplayer src=”https://s3.amazonaws.com/yazilimgunluguvideo/express+genel+bakis.mp4"]

2 thoughts on “Node.js ile Uygulama Geliştirme – 4 : REST Mimarisi ve RESTful Servisler Geliştirme [Express Framework ]

Leave a Reply

Your email address will not be published. Required fields are marked *