API Adreslerinin Hazırlanması ve Yönetimi - NOY#5

noyjavascriptoyunyoutube

1 yıl önce 0 yorum

Veritabanı bağlantılarını hazırladık. Şimdi API URL standartlarını tanılayalım.

Oyunumuzun back-end tarafı RESTful olacağı için bir view katmanına ihtiyacımız olmayacak. Şimdi yapmamız gereken bir yönlendirici oluşturmak ve bu yapıyı dinamik hale getirmek. Bunun için server/api klasörünü oluşturuyoruz.

Ardından yönlendirmeleri yapmak için server/api/routes.js dosyasına basit şekilde şu komutları yazıyoruz:

module.exports = {
    post: {
        '/v1/user': (req, res) => { res.send('Burası user') },
        '/v1/validate': (req, res) => { res.send('Burası validate') },
        '/v1/register': (req, res) => { res.send('Burası register') },
    },
    get: {},
};

Böylelikle bu dosyayı dahil ettiğimiz yerde for(var key in routes.post) gibi dinamik bir şekilde express modülümüze use edebileceğiz. 

  • /v1/user: Kullanıcılarla alakalı isteklerin yönetimi. (kullanıcı getirme, arama vb.)
  • /v1/validate: İstemcinin oturumunu doğrulama veya giriş yapma gibi isteklerin yönetimi.
  • /v1/register: Kaydedilecek değerlerin yönetimi. (Kullanıcı kayıt, oyun kayıt vb.)

Bu şekilde routes üzerinde işlem yapmamamız gerekir. Gelen isteklerin kontrolünü yapmak için server/api/controllers dizinine routes.js dosyasında yaptığımız isteklerin adında yani user.js, validate.js, register.js adında dosyalar oluşturup içlerine şu komutları yazıyoruz:

module.exports = (request, response) => {
    response.send('');
};

Controller'ı artık kullanabiliriz ancak dinamik bir şekilde require yapmak için server/api/controllers/index.js dosyasını oluşturup içine şu komutları yazıyoruz: 

exports.user = require('./user');
exports.validate = require('./validate');
exports.register = require('./register');

Controller kısmı hazır olduğuna göre bunu routes.js üzerinde kullanalım. routes.js dosyasını şu şekilde güncelleyelim:

const {
    user,
    validate,
    register,
} = require('./controllers');

module.exports = {
    post: {
        '/v1/user': user,
        '/v1/validate': validate,
        '/v1/register': register,
    },
    get: {},
};

Controller kendisine gelen parametreleri kontrol eder ve onlara göre işlem yapar. Model ise veritabanı veya veri yönetimi ile ilgilenir ve controller üzerindeki yükü alır. MVC mantığı bu şekildedir. Biz burada View kısmını kullanmayacağız çünkü bir REST yazıyoruz. Buna göre bizim model kısmını oluşturmamız gerekiyor.

Model kısmını oluşturmak için server/api/models dizinini oluşturalım ve içine veritabanı tablolarımızın isimlerini taşıyan dosyaları oluşturalım. Şu an sadece users tablomuz var. O zaman server/api/models/users.js dosyamıza şu komutları yazalım:

class Users {
    
}

module.exports = new Users();

İçerisinde bir işlem yapılmadı diğer ayarlamaları yapınca buraya geleceğiz.

Şimdi controllers için yaptığımız index.js dosyasını benzer şekilde models için de yapıyoruz. Yani server/api/models/index.js şöyle olmalı:

exports.Users = require('./users');

Baş harflerini büyük vermemizin nedeni bunların bir class olması ve controller ile karışmaması içindi.

Verileri parçalamak

Şimdi gelen request'in body değerini doldurmak için bir plugin'e ihtiyacımız var. express bizim için bunu yapan body-parser adında bir kütüphane öneriyor. Kurmak için:

npm install body-parser --save-dev

Body-parser'ın birçok özelliği var fakat biz RESTful yapımızı application/json tipinde kullanacağız. İleride fikrimiz değişirse bir sorun oluşmayacaktır. Hem uygulamıza tanımladığımız routes.js dosyasını hem de body-parser'ı kullanmak için server/uses.js dosyasındaki bazı yerlere ekleme yapalım:

...
const routes = require('./api/routes');
const bodyParser = require('body-parser')
...
        saveUninitialized: true,
    }))

    // application/json için kullanılıyor.
    app.use(bodyParser.json());

    if (routes) {
        // get için olan değerleri kullanmasını istiyoruz
        for(var key in routes.get) {
            app.get(key, routes.get[key]);
        }
        // post için olan değerleri kullanmasını istiyoruz
        for(var key in routes.post) {
            app.post(key, routes.post[key]);
        }
    }
}

Artık uygulamamıza gönderilen isteklerin yönlendirmelerini de yapmış olduk. Bunun yanında index.js dosyasına yazdığımız select methodunu silebiliriz. Yani server/index.js dosyası tamamen şöyle olmalı:

const express = require('express');
const uses = require('./uses');

// sunucumuzu oluşturalım
const app = express();
uses(app);
// yayınlayacağım port
const port = 3000;

app.listen(port, () => {
    console.log('çalışıyor');
})

Kullanıcıları Kaydetmek

Örneğin ilk logic işimizi yapalım. İlk önce database/index.js dosyasında denemek için eklediğimiz select methodunu execute diye değiştirelim:

...
    execute(...args) {
        this.client.query(...args);
    }
...

Burada kullandığımız (...args) dikkatinizi çekmiş olabilir. Bu gelen argümanları olduğu gibi args değerine aktarır, arguments keyword ile benzerlik taşır.

Sonra models/users.js dosyasına bir insert adında method ekleyelim.

const database = require('../../database');
class Users {
    // kullanıcı eklemek için kullanıyoruz.
    insert(user) {
        var sql = 'INSERT INTO users (name, email, date) VALUES ($1,$2,NOW())';
        var values = [user.name, user.email];

        return new Promise((resolve, reject) => {
            database.execute(sql, values, (err, res) => {
                if (err !== null) {
                    reject(err);
                } else {
                    resolve(true);
                }
            })
        })
    }
}

module.exports = new Users();

$1 ve $2 prepare edilecek değerleri ifade eder eğer sql içine bir kendimiz ekleseydik SQL injection güvenlik sorunu oluştururduk.

/v1/register için bir method yazalım. register çok amaç için kullanılabileceğinden ?type=user gibi bir parametre ekleyelim. Şimdi api/controllers/register.js dosyasını düzenleyelim.

const {
    Users,
} = require('../models');

module.exports = (request, response) => {
    switch(request.query.type) {
        case 'user':
            // modelimiz insert işini yapsın
            Users.insert(request.body).then(res => {
                // kullanıcı oluşturulduğu için 201 dönüyoruz
                response.status(201);
                response.send('');
            }, err => {
                // herhangi bir sorun için 500 iç sunucu hatası dönüyoruz
                response.status(500);
                response.send(err);
            });
            break;
        default:
            // eğer type farklı ise 400 Bad request olarak dönüyoruz
            response.status(400);
            response.send('');
    }
}

İyi herşey güzel böyle istek atarken 201 dönüyor ama zaten olan bir email ile tekrar istek atınca onu da veritabanına ekliyor. Bundan dolayı sorun çıkacaktır. Burada kullanıcı var mı? kontrolü yapılmalıdır. 

Kullanıcı varlığını kontrol etmek için Users modeline isExist methodu ekleyelim:

...
    isExist(email) {
        var sql = 'SELECT email FROM users WHERE email = $1';
        var values = [email];

        return new Promise((resolve, reject) => {
            database.execute(sql, values, (err, res) => {
                if (err !== null) {
                    reject(err);
                } else {
                    if (res.rows.length > 0)
                        return resolve(true); // varsa true
                    return resolve(false); // yoksa false
                }
            })
        })
    }
...

Ve bunu gerektiği yerde yani controller üzerinde yapmalıyız. O yüzden controllers/register.js dosyasındaki user case'ini şu komutlarla değiştirelim:

...
        case 'user':
            var user = request.body || {};
            // kullanıcı varlığı kontrol ediliyor
            Users.isExist(user.email).then(exist => {
                // kullanıcı varsa
                if (exist === true) {
                    // 200 dönüyor ancak error veriyor
                    response.status(200);
                    response.send({
                        error_code: 1,
                        message: 'This user alright exist.'
                    });
                    return;
                }

                Users.insert(request.body).then(res => {
                    response.status(201);
                    response.send('');
                }, err => {
                    response.status(500);
                    response.send(err);
                });
            }, err => {
                response.status(500);
                response.send(err);
            })
            break;
...

Bundan sonra aynı email ile istek atıldığında cevap 200 olacak ve error_code: 1 şeklinde gelecektir.

Bugün anlatılan noktalarda düz SQL sorguları yazdık ve bu çok amatörce. O yüzden belirli bir süre sonra bir kütüphane ile bunun daha da özelleştireceğiz. 

Bana seride yardım etmek isteyen arkadaşlara ihtiyacım oluyor eğer gönüllü yardım etmek isterseniz İletişim bilgilerimden ulaşabilirsiniz. Bugünkü konu da bu kadardı. Diğer konuda görüşmek üzere kendinize iyi bakın :)

Düşündüklerin nedir ?

Abdurrahman Eker

(1010 Eylül 11111001100)

  • Full Stack Developer at Detaysoft Turkey/Sivas
  • İnternette Avare Kodcu
  • github
  • linkedin
  • youtube
  • Yeni içeriklerden haberdar olmak ister misin ?