PostgreSQL ile Express API Arka Uç Projesi Nasıl Kurulur
Yayınlanan: 2022-03-10Testlerimizi Travis CI ve AppVeyor üzerinde kod kalitesi ve kapsam raporlamasıyla birlikte otomatik olarak çalıştırmak için Test Odaklı Geliştirme (TDD) yaklaşımını ve Sürekli Entegrasyon (CI) işini ayarlayacağız. Kontrolörler, modeller (PostgreSQL ile), hata işleme ve asenkron Express ara yazılımı hakkında bilgi edineceğiz. Son olarak, Heroku'da otomatik dağıtımı yapılandırarak CI/CD ardışık düzenini tamamlayacağız.
Kulağa çok gibi geliyor, ancak bu eğitim, belirli bir düzeyde karmaşıklığa sahip bir arka uç projede ellerini denemeye hazır olan ve tüm parçaların gerçek bir projede nasıl bir araya geldiği konusunda kafası hala karışık olan yeni başlayanlara yöneliktir. .
Ezici olmaksızın sağlamdır ve makul bir sürede tamamlayabileceğiniz bölümlere ayrılmıştır.
Başlarken
İlk adım, proje için yeni bir dizin oluşturmak ve yeni bir düğüm projesi başlatmaktır. Bu öğreticiye devam etmek için düğüm gereklidir. Eğer kurulu değilse, devam etmeden önce resmi web sitesine gidin, indirin ve kurun.
Bu proje için paket yöneticim olarak ipliği kullanacağım. Burada özel işletim sisteminiz için kurulum talimatları bulunmaktadır. İsterseniz npm kullanmaktan çekinmeyin.
Terminalinizi açın, yeni bir dizin oluşturun ve bir Node.js projesi başlatın.
# create a new directory mkdir express-api-template # change to the newly-created directory cd express-api-template # initialize a new Node.js project npm init
Bir package.json dosyası oluşturmak için aşağıdaki soruları yanıtlayın. Bu dosya projeniz hakkında bilgi içerir. Bu tür bilgilere örnek olarak, kullandığı bağımlılıklar, projeyi başlatma komutu vb.
Artık proje klasörünü seçtiğiniz düzenleyicide açabilirsiniz. Ben görsel stüdyo kodunu kullanıyorum. Hayatınızı kolaylaştıracak tonlarca eklenti içeren ücretsiz bir IDE'dir ve tüm büyük platformlarda kullanılabilir. Resmi web sitesinden indirebilirsiniz.
Proje klasöründe aşağıdaki dosyaları oluşturun:
- BENİOKU.md
- .editorconfig
EditorConfig web sitesinde .editorconfig'in ne yaptığının açıklaması burada. (Yalnız çalışıyorsanız muhtemelen buna ihtiyacınız yoktur, ancak zararı yoktur, bu yüzden burada bırakacağım.)
"EditorConfig, çeşitli editörler ve IDE'lerde aynı proje üzerinde çalışan birden fazla geliştirici için tutarlı kodlama stillerinin korunmasına yardımcı oluyor."
.editorconfig
açın ve aşağıdaki kodu yapıştırın:
root = true [*] indent_style = space indent_size = 2 charset = utf-8 trim_trailing_whitespace = false insert_final_newline = true
[*]
, altındaki kuralları projedeki her dosyaya uygulamak istediğimiz anlamına gelir. İki boşluklu bir girinti boyutu ve UTF-8
karakter kümesi istiyoruz. Ayrıca sondaki beyaz alanı kırpmak ve dosyamıza son bir boş satır eklemek istiyoruz.
README.md dosyasını açın ve proje adını birinci düzey öğe olarak ekleyin.
# Express API template
Hemen sürüm kontrolünü ekleyelim.
# initialize the project folder as a git repository git init
Bir .gitignore dosyası oluşturun ve aşağıdaki satırları girin:
node_modules/ yarn-error.log .env .nyc_output coverage build/
Bunlar, izlemek istemediğimiz tüm dosya ve klasörlerdir. Henüz projemizde yok ama ilerledikçe göreceğiz.
Bu noktada aşağıdaki klasör yapısına sahip olmalısınız.
EXPRESS-API-TEMPLATE ├── .editorconfig ├── .gitignore ├── package.json └── README.md
Bunu, değişikliklerimi gerçekleştirmek ve GitHub'a göndermek için iyi bir nokta olarak görüyorum.
Yeni Bir Ekspres Projesine Başlamak
Express, web uygulamaları oluşturmaya yönelik bir Node.js çerçevesidir. Resmi web sitesine göre, bu bir
Node.js için hızlı, bağımsız, minimalist web çerçevesi.
Node.js için başka harika web uygulama çerçeveleri de var, ancak Express, bu yazının yazıldığı sırada 47k'den fazla GitHub yıldızıyla çok popüler.
Bu yazıda Express'i oluşturan tüm parçalar hakkında çok fazla tartışmayacağız. Bu tartışma için Jamie'nin serisine bakmanızı tavsiye ederim. İlk bölüm burada, ikinci bölüm burada.
Express'i yükleyin ve yeni bir Express projesi başlatın. Bir Express sunucusunu sıfırdan manuel olarak kurmak mümkündür, ancak hayatımızı kolaylaştırmak için uygulama iskeletini kurmak için ekspres oluşturucuyu kullanacağız.
# install the express generator globally yarn global add express-generator # install express yarn add express # generate the express project in the current folder express -f
-f
bayrağı, Express'i projeyi geçerli dizinde oluşturmaya zorlar.
Şimdi bazı ev temizleme işlemleri yapacağız.
- index/users.js dosyasını silin.
-
public/
veviews/
klasörlerini silin. - bin/www dosyasını bin /www.js olarak yeniden adlandırın.
-
jade
kaldır komutuylayarn remove jade
. -
src/
adında yeni bir klasör oluşturun ve aşağıdakini içine taşıyın: 1. app.js dosyası 2.bin/
klasörü 3. içindekiroutes/
klasör. - package.json dosyasını açın ve
start
betiğini aşağıdaki gibi görünecek şekilde güncelleyin.
"start": "node ./src/bin/www"
Bu noktada proje klasör yapınız aşağıdaki gibidir. VS Kodunun gerçekleşen dosya değişikliklerini nasıl vurguladığını görebilirsiniz.
EXPRESS-API-TEMPLATE ├── node_modules ├── src | ├── bin │ │ ├── www.js │ ├── routes │ | ├── index.js │ └── app.js ├── .editorconfig ├── .gitignore ├── package.json ├── README.md └── yarn.lock
src/app.js dosyasını açın ve içeriği aşağıdaki kodla değiştirin.
var logger = require('morgan'); var express = require('express'); var cookieParser = require('cookie-parser'); var indexRouter = require('./routes/index'); var app = express(); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use('/v1', indexRouter); module.exports = app;
Bazı kitaplıklara ihtiyaç duyduktan sonra, Express'e /v1
gelen her isteği indexRouter
ile işlemesini söyleriz.
route/index.js içeriğini aşağıdaki kodla değiştirin:
var express = require('express'); var router = express.Router(); router.get('/', function(req, res, next) { return res.status(200).json({ message: 'Welcome to Express API template' }); }); module.exports = router;
Express'i alıyoruz, ondan bir yönlendirici oluşturuyoruz ve 200
durum kodunu ve bir JSON mesajı döndüren /
rotasını sunuyoruz.
Uygulamayı aşağıdaki komutla başlatın:
# start the app yarn start
Her şeyi doğru kurduysanız, terminalinizde yalnızca $ node ./src/bin/www
.
Tarayıcınızda https://localhost:3000/v1
adresini ziyaret edin. Aşağıdaki mesajı görmelisiniz:
{ "message": "Welcome to Express API template" }
Bu, değişikliklerimizi taahhüt etmek için iyi bir nokta.
- Depomdaki ilgili şube 01-install-express.
ES6
Dönüştürmek
express-generator
tarafından oluşturulan kod ES5
, ancak bu yazıda tüm ES6
sözdiziminde yazacağız. O halde mevcut kodumuzu ES6
.
route/index.js içeriğini aşağıdaki kodla değiştirin:
import express from 'express'; const indexRouter = express.Router(); indexRouter.get('/', (req, res) => res.status(200).json({ message: 'Welcome to Express API template' }) ); export default indexRouter;
Yukarıda gördüğümüzle aynı koddur, ancak import ifadesi ve /
route işleyicisinde bir ok işlevi vardır.
src/app.js içeriğini aşağıdaki kodla değiştirin:
import logger from 'morgan'; import express from 'express'; import cookieParser from 'cookie-parser'; import indexRouter from './routes/index'; const app = express(); app.use(logger('dev')); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use('/v1', indexRouter); export default app;
Şimdi src/bin/www.js içeriğine bir göz atalım. Kademeli olarak inşa edeceğiz. src/bin/www.js
içeriğini silin ve aşağıdaki kod bloğuna yapıştırın.
#!/usr/bin/env node /** * Module dependencies. */ import debug from 'debug'; import http from 'http'; import app from '../app'; /** * Normalize a port into a number, string, or false. */ const normalizePort = val => { const port = parseInt(val, 10); if (Number.isNaN(port)) { // named pipe return val; } if (port >= 0) { // port number return port; } return false; }; /** * Get port from environment and store in Express. */ const port = normalizePort(process.env.PORT || '3000'); app.set('port', port); /** * Create HTTP server. */ const server = http.createServer(app); // next code block goes here
Bu kod, ortam değişkenlerinde özel bir bağlantı noktasının belirtilip belirtilmediğini kontrol eder. Hiçbiri ayarlanmazsa, normalizePort tarafından bir dizeye veya sayıya normalizePort
sonra, uygulama örneğinde varsayılan bağlantı noktası değeri olan 3000
ayarlanır. Sunucu daha sonra geri arama işlevi olarak app
ile http
modülünden oluşturulur.
#!/usr/bin/env node
satırı, bu dosyayı çalıştırmak istediğimizde düğümü belirteceğimiz için isteğe bağlıdır. Ancak src/bin/www.js dosyasının 1. satırında olduğundan emin olun veya tamamen kaldırın.
Hata işleme fonksiyonuna bir göz atalım. Bu kod bloğunu sunucunun oluşturulduğu satırdan sonra kopyalayıp yapıştırın.
/** * Event listener for HTTP server "error" event. */ const onError = error => { if (error.syscall !== 'listen') { throw error; } const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; // handle specific listen errors with friendly messages switch (error.code) { case 'EACCES': alert(`${bind} requires elevated privileges`); process.exit(1); break; case 'EADDRINUSE': alert(`${bind} is already in use`); process.exit(1); break; default: throw error; } }; /** * Event listener for HTTP server "listening" event. */ const onListening = () => { const addr = server.address(); const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; debug(`Listening on ${bind}`); }; /** * Listen on provided port, on all network interfaces. */ server.listen(port); server.on('error', onError); server.on('listening', onListening);
onError
işlevi, http sunucusundaki hataları dinler ve uygun hata mesajlarını görüntüler. onListening
işlevi, sunucunun konsola dinlediği bağlantı noktasının çıktısını verir. Son olarak, sunucu belirtilen adres ve bağlantı noktasından gelen istekleri dinler.
Bu noktada mevcut tüm ES6
sözdizimindedir. Sunucunuzu durdurun ( Ctrl + C kullanın) ve thread yarn start
. SyntaxError: Invalid or unexpected token
hatası alırsınız. Bunun nedeni, Node'un (yazma sırasında) kodumuzda kullandığımız bazı sözdizimlerini desteklememesidir.
Şimdi bunu aşağıdaki bölümde düzelteceğiz.
Geliştirme Bağımlılıklarını Yapılandırma: babel
, nodemon
, eslint
, And prettier
Projenin bu aşamasında ihtiyaç duyacağımız komut dosyalarının çoğunu kurmanın zamanı geldi.
Aşağıdaki komutlarla gerekli kütüphaneleri kurun. Her şeyi kopyalayıp terminalinize yapıştırabilirsiniz. Yorum satırları atlanacak.
# install babel scripts yarn add @babel/cli @babel/core @babel/plugin-transform-runtime @babel/preset-env @babel/register @babel/runtime @babel/node --dev
Bu, listelenen tüm babel komut dosyalarını geliştirme bağımlılıkları olarak yükler. package.json dosyanızı kontrol edin ve bir devDependencies
bölümü görmelisiniz. Yüklü tüm komut dosyaları burada listelenecektir.
Kullandığımız babel scriptleri aşağıda açıklanmıştır:
@babel/cli | babel kullanmak için gerekli bir kurulum. Babel'in terminalden kullanılmasına izin verir ve ./node_modules/.bin/babel olarak bulunur. |
@babel/core | Temel Babel işlevselliği. Bu gerekli bir kurulumdur. |
@babel/node | Bu tam olarak Node.js CLI gibi çalışır ve babel ön ayarları ve eklentileri ile derlemenin ek yararı vardır. Bu, nodemon ile kullanım için gereklidir. |
@babel/plugin-transform-runtime | Bu, derlenmiş çıktıda tekrarı önlemeye yardımcı olur. |
@babel/preset-env | Kod dönüşümlerini gerçekleştirmekten sorumlu eklentiler koleksiyonu. |
@babel/register | Bu, dosyaları anında derler ve testler sırasında bir gereklilik olarak belirtilir. |
@babel/runtime | Bu, @babel/plugin-transform-runtime ile birlikte çalışır. |
Projenizin kökünde .babelrc adında bir dosya oluşturun ve aşağıdaki kodu ekleyin:
{ "presets": ["@babel/preset-env"], "plugins": ["@babel/transform-runtime"] }
nodemon
# install nodemon yarn add nodemon --dev
nodemon
, proje kaynak kodumuzu izleyen ve herhangi bir değişiklik gözlemlediğinde sunucumuzu otomatik olarak yeniden başlatan bir kütüphanedir.
Projenizin kökünde nodemon.json adında bir dosya oluşturun ve aşağıdaki kodu ekleyin:
{ "watch": [ "package.json", "nodemon.json", ".eslintrc.json", ".babelrc", ".prettierrc", "src/" ], "verbose": true, "ignore": ["*.test.js", "*.spec.js"] }
watch
tuşu, nodemon
hangi dosya ve klasörlerin değişiklikleri izleyeceğini söyler. Bu nedenle, bu dosyalardan herhangi biri değiştiğinde, nodemon sunucuyu yeniden başlatır. ignore
tuşu, dosyaların değişiklikleri izlememesini söyler.
Şimdi package.json dosyanızın scripts
bölümünü aşağıdaki gibi görünecek şekilde güncelleyin:
# build the content of the src folder "prestart": "babel ./src --out-dir build" # start server from the build folder "start": "node ./build/bin/www" # start server in development mode "startdev": "nodemon --exec babel-node ./src/bin/www"
-
prestart
komut dosyaları,src/
klasörünün içeriğini oluşturur ve bunubuild/
klasörüne yerleştirir.yarn start
komutunu verdiğinizde, bu komut dosyası,start
komut dosyasından önce çalışır. -
start
betiği şimdi daha önce sunduğumuzsrc/
klasörü yerinebuild/
klasörünün içeriğini sunuyor. Bu, dosyayı üretimde sunarken kullanacağınız komut dosyasıdır. Aslında, Heroku gibi hizmetler, dağıttığınızda bu betiği otomatik olarak çalıştırır. -
yarn startdev
, geliştirme sırasında sunucuyu başlatmak için kullanılır. Şu andan itibaren uygulamayı geliştirirken bu betiği kullanacağız. Uygulamayı çalıştırmak için artık normalnode
yerinebabel-node
kullandığımıza dikkat edin.--exec
bayrağı,babel-node
src/
klasörüne hizmet vermeye zorlar.start
betiği için,build/
klasöründeki dosyalar ES5'e derlendiğindennode
kullanıyoruz.
yarn startdev
çalıştırın ve https://localhost:3000/v1 adresini ziyaret edin. Sunucunuz tekrar çalışır durumda olmalıdır.
Bu bölümdeki son adım, ESLint
ve prettier
yapılandırmaktır. ESLint, sözdizimi kurallarının uygulanmasına yardımcı olurken, prettier, kodumuzu okunabilirlik için uygun şekilde biçimlendirmeye yardımcı olur.
Her ikisini de aşağıdaki komutla ekleyin. Sunucumuzun çalıştığı terminali gözlemlerken bunu ayrı bir terminalde çalıştırmalısınız. Sunucunun yeniden başlatıldığını görmelisiniz. Bunun nedeni, package.json dosyasını değişiklikler için izliyor olmamızdır.
# install elsint and prettier yarn add eslint eslint-config-airbnb-base eslint-plugin-import prettier --dev
Şimdi proje root
.eslintrc.json dosyasını oluşturun ve aşağıdaki kodu ekleyin:
{ "env": { "browser": true, "es6": true, "node": true, "mocha": true }, "extends": ["airbnb-base"], "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parserOptions": { "ecmaVersion": 2018, "sourceType": "module" }, "rules": { "indent": ["warn", 2], "linebreak-style": ["error", "unix"], "quotes": ["error", "single"], "semi": ["error", "always"], "no-console": 1, "comma-dangle": [0], "arrow-parens": [0], "object-curly-spacing": ["warn", "always"], "array-bracket-spacing": ["warn", "always"], "import/prefer-default-export": [0] } }
Bu dosya çoğunlukla eslint
kontrol edeceği bazı kuralları tanımlar. Airbnb tarafından kullanılan stil kurallarını genişlettiğimizi görebilirsiniz.
"rules"
bölümünde, eslint
belirli ihlallerle karşılaştığında uyarı mı yoksa hata mı göstermesi gerektiğini tanımlıyoruz. Örneğin, 2 boşluk kullanılmayan herhangi bir girinti için terminalimizde bir uyarı mesajı gösterir. [0]
değeri bir kuralı kapatır; bu, kuralı ihlal edersek bir uyarı veya hata almayacağımız anlamına gelir.
.prettierrc adlı bir dosya oluşturun ve aşağıdaki kodu ekleyin:
{ "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": true }
Sekme genişliğini 2
olarak ayarlıyoruz ve uygulamamız boyunca tek tırnak kullanımını zorunlu kılıyoruz. Daha fazla stil seçeneği için daha güzel kılavuzu kontrol edin.
Şimdi aşağıdaki komut dosyalarını package.json dosyanıza ekleyin:
# add these one after the other "lint": "./node_modules/.bin/eslint ./src" "pretty": "prettier --write '**/*.{js,json}' '!node_modules/**'" "postpretty": "yarn lint --fix"
yarn lint
çalıştırın. Konsolda bir dizi hata ve uyarı görmelisiniz.
pretty
komutu kodumuzu güzelleştirir. postpretty
komutu hemen ardından çalıştırılır. --fix
bayrağı eklenmiş olarak lint
komutunu çalıştırır. Bu bayrak, ESLint
yaygın linting sorunlarını otomatik olarak düzeltmesini söyler. Bu şekilde, lint
komutuna hiç aldırış etmeden, daha çok yarn pretty
komutunu çalıştırıyorum.
yarn pretty
çalıştırın. bin/www.js dosyasında alert
varlığına dair sadece iki uyarımız olduğunu görmelisiniz.
İşte bu noktada proje yapımız nasıl görünüyor.
EXPRESS-API-TEMPLATE ├── build ├── node_modules ├── src | ├── bin │ │ ├── www.js │ ├── routes │ | ├── index.js │ └── app.js ├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .gitignore ├── .prettierrc ├── nodemon.json ├── package.json ├── README.md └── yarn.lock
Proje yarn-error.log
ek bir dosyanız olduğunu görebilirsiniz. .gitignore
dosyasına ekleyin. Değişikliklerinizi taahhüt edin.
- Depomda bu noktada karşılık gelen dal 02-dev-bağımlılıklarıdır.
.env Dosyamızdaki Ayarlar ve Ortam Değişkenleri
Hemen hemen her projede, uygulamanız genelinde kullanılacak ayarları depolamak için bir yere ihtiyacınız olacak, örneğin bir AWS gizli anahtarı. Bu tür ayarları ortam değişkenleri olarak saklarız. Bu onları meraklı gözlerden uzak tutar ve gerektiğinde uygulamamız içinde kullanabiliriz.
Tüm ortam değişkenlerimi okuduğum bir settings.js dosyasına sahip olmayı seviyorum. Ardından, uygulamamın herhangi bir yerinden ayarlar dosyasına başvurabilirim. Bu dosyaya istediğiniz adı vermekte özgürsünüz, ancak bu tür dosyaların settings.js veya config.js olarak adlandırılması konusunda bir tür fikir birliği var.
Ortam değişkenlerimiz için onları bir .env
dosyasında tutacağız ve oradan settings
dosyamıza okuyacağız.
Projenizin kökünde .env dosyasını oluşturun ve aşağıdaki satırı girin:
TEST_ENV_VARIABLE="Environment variable is coming across"
Projemizde ortam değişkenlerini okuyabilmek için .env
dosyamızı okuyan ve içinde tanımlanan ortam değişkenlerine erişmemizi sağlayan güzel bir kitaplık dotenv
var. Hadi yükleyelim.
# install dotenv yarn add dotenv
.env dosyasını nodemon
tarafından izlenen dosyalar listesine ekleyin.
Şimdi src/
klasörü içinde settings.js dosyasını oluşturun ve aşağıdaki kodu ekleyin:
import dotenv from 'dotenv'; dotenv.config(); export const testEnvironmentVariable = process.env.TEST_ENV_VARIABLE;
dotenv
paketini içe aktarıyoruz ve yapılandırma yöntemini çağırıyoruz. Daha sonra .env
dosyamızda belirlediğimiz testEnvironmentVariable
dışa aktarıyoruz.
src/routes/index.js dosyasını açın ve kodu aşağıdaki ile değiştirin.
import express from 'express'; import { testEnvironmentVariable } from '../settings'; const indexRouter = express.Router(); indexRouter.get('/', (req, res) => res.status(200).json({ message: testEnvironmentVariable })); export default indexRouter;
Burada yaptığımız tek değişiklik, testEnvironmentVariable'ı settings
dosyamızdan içe aktarmamız ve /
testEnvironmentVariable
gelen bir istek için dönüş mesajı olarak kullanmamızdır.
https://localhost:3000/v1 adresini ziyaret edin ve mesajı aşağıda gösterildiği gibi görmelisiniz.
{ "message": "Environment variable is coming across." }
Ve bu kadar. Artık istediğimiz kadar ortam değişkeni ekleyebilir ve bunları settings.js dosyamızdan dışa aktarabiliriz.
Bu, kodunuzu işlemek için iyi bir nokta. Kodunuzu güzelleştirmeyi ve tiftiklemeyi unutmayın.
- Depomdaki ilgili dal 03-env-değişkenleridir.
İlk Testimizi Yazıyoruz
Testi uygulamamıza dahil etmenin zamanı geldi. Geliştiriciye kodunda güven veren şeylerden biri de testler. Web'de Test Odaklı Geliştirme (TDD) hakkında vaaz veren sayısız makale görmüşsünüzdür. Kodunuzun bir miktar teste ihtiyacı olduğu yeterince vurgulanamaz. Express.js ile çalışırken TDD'yi takip etmek çok kolaydır.
Testlerimizde, API uç noktalarımıza çağrılar yapacağız ve geri dönenin beklediğimiz gibi olup olmadığını kontrol edeceğiz.
Gerekli bağımlılıkları yükleyin:
# install dependencies yarn add mocha chai nyc sinon-chai supertest coveralls --dev
Bu kitaplıkların her birinin testlerimizde oynayacağı kendi rolü vardır.
mocha | test koşucusu |
chai | iddialarda bulunmak için kullanılır |
nyc | test kapsamı raporunu topla |
sinon-chai | chai'nin iddialarını genişletiyor |
supertest | API uç noktalarımıza HTTP çağrıları yapmak için kullanılır |
coveralls | coveralls.io'ya test kapsamı yüklemek için |
Projenizin kökünde yeni bir test/
klasör oluşturun. Bu klasörün içinde iki dosya oluşturun:
- test/setup.js
- test/index.test.js
Mocha, test/
klasörü otomatik olarak bulacaktır.
test/setup.js dosyasını açın ve aşağıdaki kodu yapıştırın. Bu, test dosyalarımızda ihtiyacımız olan tüm içe aktarmaları düzenlememize yardımcı olan bir yardımcı dosyadır.
import supertest from 'supertest'; import chai from 'chai'; import sinonChai from 'sinon-chai'; import app from '../src/app'; chai.use(sinonChai); export const { expect } = chai; export const server = supertest.agent(app); export const BASE_URL = '/v1';
Bu bir ayar dosyası gibidir, ancak testlerimiz içindir. Bu şekilde, test dosyalarımızın her birinin içindeki her şeyi başlatmamız gerekmez. Bu yüzden gerekli paketleri içe aktarır ve başlattığımızı dışa aktarırız - bunları daha sonra bunlara ihtiyaç duyan dosyalara aktarabiliriz.
index.test.js dosyasını açın ve aşağıdaki test kodunu yapıştırın.
import { expect, server, BASE_URL } from './setup'; describe('Index page test', () => { it('gets base url', done => { server .get(`${BASE_URL}/`) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.message).to.equal( 'Environment variable is coming across.' ); done(); }); }); });
Burada, /
ve res.
body
nesnesi, Environment variable is coming across.
değerine sahip bir message
anahtarına sahiptir.
Açıklama , it
modeline aşina değilseniz, describe
“Başlarken” belgesine hızlı bir göz atmanızı tavsiye ederim.
package.json scripts
bölümüne test komutunu ekleyin.
"test": "nyc --reporter=html --reporter=text --reporter=lcov mocha -r @babel/register"
Bu komut dosyası, testimizi nyc
ile yürütür ve üç tür kapsam raporu oluşturur: coverage/
klasöre çıkarılan bir HTML raporu; terminale çıkarılan bir metin raporu ve .nyc_output/
klasörüne çıkarılan bir lcov raporu.
Şimdi yarn test
çalıştırın. Aşağıdaki fotoğraftaki gibi terminalinizde bir metin raporu görmelisiniz.

İki ek klasörün oluşturulduğuna dikkat edin:
-
.nyc_output/
-
coverage/
.gitignore
içine bakın ve her ikisini de zaten görmezden geldiğimizi göreceksiniz. Bir tarayıcıda coverage/index.html
dosyasını açmanızı ve her dosya için test raporunu görüntülemenizi tavsiye ederim.
Bu, değişikliklerinizi taahhüt etmek için iyi bir nokta.
- Depomdaki ilgili dal 04 ilk testtir.
Sürekli Entegrasyon(CD) ve Rozetler: Travis, Tulumlar, Code Climate, AppVeyor
Artık sürekli entegrasyon ve dağıtım (CI/CD) araçlarını yapılandırmanın zamanı geldi. travis-ci
, coveralls
, AppVeyor
ve codeclimate
gibi ortak hizmetleri yapılandıracağız ve README dosyamıza rozetler ekleyeceğiz.
Başlayalım.
Travis CI
Travis CI, GitHub'a (ve son zamanlarda Bitbucket'e) bir taahhütte bulunduğumuzda ve her çekme isteği oluşturduğumuzda testlerimizi otomatik olarak çalıştıran bir araçtır. Bu, çoğunlukla, yeni kodumuzun testlerimizden herhangi birini kırıp kırmadığını bize göstererek çekme istekleri yaparken kullanışlıdır.
- travis-ci.com veya travis-ci.org adresini ziyaret edin ve hesabınız yoksa bir hesap oluşturun. GitHub hesabınızla kaydolmanız gerekir.
- Profil resminizin yanındaki açılır okun üzerine gelin ve
settings
tıklayın. -
Repositories
sekmesi altında Github'a yönlendirilmek için Github'dakiManage repositories on Github
tıklayın. - GitHub sayfasında,
Repository access
seçeneğine ilerleyin veOnly select repositories
yanındaki onay kutusunu tıklayın. -
Select repositories
açılır menüsünü tıklayın veexpress-api-template
deposunu bulun.travis-ci
eklemek istediğiniz depolar listesine eklemek için tıklayın. -
Approve and install
tıklayın vetravis-ci
yeniden yönlendirilmeyi bekleyin. - Depo sayfasının üst kısmında, depo adının yanında,
build unknown
simgesine tıklayın. Durum Görüntüsü modundan, biçim açılır menüsünden işaretlemeyi seçin. - Ortaya çıkan kodu kopyalayın ve README.md dosyanıza yapıştırın.
- Proje sayfasında,
More options
>Settings
tıklayın.Environment Variables
bölümü altında,TEST_ENV_VARIABLE
env değişkenini ekleyin. Değerini girerken,"Environment variable is coming across."
- Projenizin kökünde .travis.yml dosyası oluşturun ve aşağıdaki kodu yapıştırın (Code Climate bölümünde
CC_TEST_REPORTER_ID
değerini ayarlayacağız).
language: node_js env: global: - CC_TEST_REPORTER_ID=get-this-from-code-climate-repo-page matrix: include: - node_js: '12' cache: directories: [node_modules] install: yarn after_success: yarn coverage before_script: - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - ./cc-test-reporter before-build script: - yarn test after_script: - ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESUL
Önce Travis'e testimizi Node.js ile çalıştırmasını söyleriz, ardından CC_TEST_REPORTER_ID
global ortam değişkenini ayarlarız (buna Kod İklimi bölümünde geleceğiz). matrix
bölümünde Travis'e testlerimizi Node.js v12 ile çalıştırmasını söylüyoruz. Ayrıca node_modules/
dizinini önbelleğe almak istiyoruz, böylece her seferinde yeniden oluşturulması gerekmez.
Bağımlılıklarımızı, yarn install
kısaltması olan yarn
komutunu kullanarak kuruyoruz. before_script
ve after_script
komutları, kapsam sonuçlarını codeclimate
yüklemek için kullanılır. Kısa süre codeclimate
yapılandıracağız. yarn test
başarıyla tamamlandıktan sonra, kapsama raporumuzu coveralls.io'ya yükleyecek olan yarn coverage
da çalıştırmak istiyoruz.
Tulumlar
Tulumlar, kolay görselleştirme için test kapsamı verilerini yükler. Yerel makinemizdeki test kapsamını kapsam klasöründen görebiliriz, ancak Tulumlar bunu yerel makinemizin dışında kullanılabilir hale getirir.
- coveralls.io'yu ziyaret edin ve ya oturum açın ya da Github hesabınızla kaydolun.
- Gezinme menüsünü ortaya çıkarmak için ekranın sol tarafının üzerine gelin.
ADD REPOS
üzerine tıklayın. -
express-api-template
arayın ve sol taraftaki geçiş düğmesini kullanarak kapsamı açın. Bulamazsanız, sağ üst köşedekiSYNC REPOS
tıklayın ve tekrar deneyin. PRO hesabınız yoksa, deponuzun herkese açık olması gerektiğini unutmayın. - Depo ayrıntıları sayfasına gitmek için ayrıntılara tıklayın.
- Projenizin kökünde .coveralls.yml dosyasını oluşturun ve aşağıdaki kodu girin.
repo_token
almak için repo ayrıntılarına tıklayın. O sayfada kolayca bulacaksınız.repo_token
için bir tarayıcı araması yapabilirsiniz.
repo_token: get-this-from-repo-settings-on-coveralls.io
Bu belirteç, kapsama verilerinizi Tulumlardaki bir depoya eşler. Şimdi, package.json dosyanızın scripts
bölümüne coverage
komutunu ekleyin:
"coverage": "nyc report --reporter=text-lcov | coveralls"
Bu komut, .nyc_output
klasöründeki kapsam raporunu coveralls.io'ya yükler. İnternet bağlantınızı açın ve çalıştırın:
yarn coverage
Bu, mevcut kapsam raporunu tulumlara yüklemelidir. Raporun tamamını görmek için tulum repo sayfasını yenileyin.
Ayrıntılar sayfasında, BADGE YOUR REPO
bölümünü bulmak için aşağı kaydırın. EMBED
açılır menüsüne tıklayın ve işaretleme kodunu kopyalayın ve BENİOKU dosyanıza yapıştırın.
Kod İklim
Code Climate, kod kalitesini ölçmemize yardımcı olan bir araçtır. Bazı tanımlanmış kalıplara karşı kodumuzu kontrol ederek bize bakım metriklerini gösterir. Gereksiz tekrarlar ve derinden iç içe for döngüleri gibi şeyleri algılar. Aynı zamanda coveralls.io gibi test kapsamı verilerini de toplar.
- codeclimate.com adresini ziyaret edin ve 'GitHub ile Kaydolun' seçeneğini tıklayın. Zaten bir hesabınız varsa oturum açın.
- Kontrol panelinize girdikten sonra,
Add a repository
'yi tıklayın. - Listeden
express-api-template
bulun veAdd Repo
tıklayın. - Derlemenin tamamlanmasını ve depo panosuna yönlendirilmesini bekleyin.
-
Codebase Summary
altında,Test Coverage
Et'e tıklayın.Test coverage
menüsü altında,TEST REPORTER ID
kopyalayın ve .travis.yml dosyanıza CC_TEST_REPORTER_ID değeri olarakCC_TEST_REPORTER_ID
. - Yine aynı sayfada, sol taraftaki gezinmede,
EXTRAS
altında Rozetler'e tıklayın.maintainability
yapılabilirlik vetest coverage
rozetlerini markdown formatında kopyalayın ve README.md dosyanıza yapıştırın.
Bakım yapılabilirlik kontrollerini yapılandırmanın iki yolu olduğunu unutmamak önemlidir. Her depoya uygulanan varsayılan ayarlar vardır, ancak isterseniz projenizin kökünde bir .codeclimate.yml dosyası sağlayabilirsiniz. Depo ayarları sayfasının Maintainability
sekmesinde bulabileceğiniz varsayılan ayarları kullanacağım. En azından bir göz atmanızı tavsiye ederim. Yine de kendi ayarlarınızı yapılandırmak istiyorsanız, bu kılavuz size ihtiyacınız olan tüm bilgileri verecektir.

AppVeyor
AppVeyor ve Travis CI, otomatik test çalıştırıcılarıdır. Temel fark, travis-ci'nin testleri Linux ortamında çalıştırırken AppVeyor'un Windows ortamında testleri çalıştırmasıdır. Bu bölüm, AppVeyor'a nasıl başlayacağınızı göstermek için eklenmiştir.
- AppVeyor'u ziyaret edin ve giriş yapın veya kaydolun.
- Bir sonraki sayfada,
NEW PROJECT
üzerine tıklayın. - Depo listesinden
express-api-template
bulun. Üzerine gelin veADD
tıklayın. -
Settings
sekmesine tıklayın. Sol gezinmedeEnvironment
tıklayın.TEST_ENV_VARIABLE
ve değerini ekleyin. Sayfanın altındaki 'Kaydet'i tıklayın. - Projenizin kökünde appveyor.yml dosyasını oluşturun ve aşağıdaki kodu yapıştırın.
environment: matrix: - nodejs_version: "12" install: - yarn test_script: - yarn test build: off
Bu kod, AppVeyor'a testlerimizi Node.js v12 kullanarak çalıştırmasını söyler. Daha sonra yarn
komutu ile proje bağımlılıklarımızı kuruyoruz. test_script
, testimizi çalıştıracak komutu belirtir. Son satır, AppVeyor'a bir derleme klasörü oluşturmamasını söyler.
Settings
sekmesine tıklayın. Sol taraftaki gezinme panelinde rozetlere tıklayın. İşaretleme kodunu kopyalayın ve README.md dosyanıza yapıştırın.
Kodunuzu girin ve GitHub'a gönderin. Her şeyi anlatıldığı gibi yaptıysanız, tüm testler geçmeli ve aşağıda gösterildiği gibi parlak yeni rozetlerinizi görmelisiniz. Travis ve AppVeyor'da ortam değişkenlerini ayarladığınızı tekrar kontrol edin.

Şimdi değişikliklerimizi taahhüt etmek için iyi bir zaman.
- Depomdaki ilgili şube 05-ci.
Denetleyici Ekleme
Şu anda, src/routes/index.js içindeki /v1
kök URL'sine yönelik GET
isteğini işliyoruz. Bu beklendiği gibi çalışıyor ve bunda yanlış bir şey yok. Ancak, uygulamanız büyüdükçe her şeyi düzenli tutmak istersiniz. Endişelerin ayrılmasını istiyorsunuz - isteği işleyen kod ile müşteriye geri gönderilecek yanıtı oluşturan kod arasında net bir ayrım istiyorsunuz. Bunu başarmak için controllers
yazıyoruz. Denetleyiciler, belirli bir URL üzerinden gelen istekleri işleyen işlevlerdir.
Başlamak için, src/
klasörünün içinde bir controllers/
klasörü oluşturun. İç controllers
iki dosya oluşturur: index.js ve home.js . Fonksiyonlarımızı index.js içinden dışa aktarırdık. home.js'ye istediğiniz herhangi bir ad verebilirsiniz, ancak genellikle denetleyicileri kontrol ettikleri şeyden sonra adlandırmak istersiniz. Örneğin, uygulamanızdaki kullanıcılarla ilgili her işlevi tutmak için bir usersController.js dosyanız olabilir.
src/controllers/home.js dosyasını açın ve aşağıdaki kodu girin:
import { testEnvironmentVariable } from '../settings'; export const indexPage = (req, res) => res.status(200).json({ message: testEnvironmentVariable });
Yalnızca /
rotası için talebi işleyen işlevi taşıdığımızı fark edeceksiniz.
src/controllers/index.js dosyasını açın ve aşağıdaki kodu girin.
// export everything from home.js export * from './home';
Her şeyi home.js dosyasından dışa aktarıyoruz. Bu, içe aktarma ifadelerimizi import { indexPage } from '../controllers';
src/routes/index.js dosyasını açın ve oradaki kodu aşağıdaki kodla değiştirin:
import express from 'express'; import { indexPage } from '../controllers'; const indexRouter = express.Router(); indexRouter.get('/', indexPage); export default indexRouter;
Buradaki tek değişiklik, /
rotaya yapılan isteği işlemek için bir işlev sağlamış olmamızdır.
İlk denetleyicinizi başarıyla yazdınız. Buradan, gerektiğinde daha fazla dosya ve işlev ekleme meselesi.
Devam edin ve birkaç rota ve kontrolör ekleyerek uygulamayla oynayın. Hakkında sayfası için bir rota ve bir denetleyici ekleyebilirsiniz. Yine de testinizi güncellemeyi unutmayın.
Hiçbir şeyi kırmadığımızı doğrulamak için yarn test
yapın. Testin geçer mi? Çok havalı.
Bu, değişikliklerimizi taahhüt etmek için iyi bir nokta.
- Depomdaki ilgili dal 06 denetleyicisidir.
PostgreSQL
Veritabanını Bağlama ve Model Yazma
Denetleyicimiz şu anda sabit kodlanmış metin mesajları döndürüyor. Gerçek dünyadaki bir uygulamada, genellikle bir veritabanından bilgi depolamamız ve almamız gerekir. Bu bölümde uygulamamızı bir PostgreSQL veritabanına bağlayacağız.
Bir veritabanı kullanarak basit metin mesajlarının depolanmasını ve alınmasını uygulayacağız. Bir veritabanı ayarlamak için iki seçeneğimiz var: birini bir bulut sunucusundan sağlayabiliriz veya kendi yerel olarak kurabiliriz.
Bir bulut sunucusundan bir veritabanı sağlamanızı tavsiye ederim. ElephantSQL has a free plan that gives 20MB of free storage which is sufficient for this tutorial. Visit the site and click on Get a managed database today
. Create an account (if you don't have one) and follow the instructions to create a free plan. Take note of the URL on the database details page. We'll be needing it soon.

If you would rather set up a database locally, you should visit the PostgreSQL and PgAdmin sites for further instructions.
Once we have a database set up, we need to find a way to allow our Express app to communicate with our database. Node.js by default doesn't support reading and writing to PostgreSQL
database, so we'll be using an excellent library, appropriately named, node-postgres.
node-postgres
executes SQL
queries in node and returns the result as an object, from which we can grab items from the rows key.
Let's connect node-postgres
to our application.
# install node-postgres yarn add pg
Open settings.js and add the line below:
export const connectionString = process.env.CONNECTION_STRING;
Open your .env
file and add the CONNECTION_STRING
variable. This is the connection string we'll be using to establish a connection to our database. The general form of the connection string is shown below.
CONNECTION_STRING="postgresql://dbuser:dbpassword@localhost:5432/dbname"
If you're using elephantSQL you should copy the URL from the database details page.
Inside your /src
folder, create a new folder called models/
. Inside this folder, create two files:
- pool.js
- model.js
Open pools.js and paste the following code:
import { Pool } from 'pg'; import dotenv from 'dotenv'; import { connectionString } from '../settings'; dotenv.config(); export const pool = new Pool({ connectionString });
First, we import the Pool
and dotenv
from the pg
and dotenv
packages, and then import the settings we created for our postgres database before initializing dotenv
. We establish a connection to our database with the Pool
object. In node-postgres
, every query is executed by a client. A Pool is a collection of clients for communicating with the database.
To create the connection, the pool constructor takes a config object. You can read more about all the possible configurations here. It also accepts a single connection string, which I will use here.
Open model.js and paste the following code:
import { pool } from './pool'; class Model { constructor(table) { this.pool = pool; this.table = table; this.pool.on('error', (err, client) => `Error, ${err}, on idle client${client}`); } async select(columns, clause) { let query = `SELECT ${columns} FROM ${this.table}`; if (clause) query += clause; return this.pool.query(query); } } export default Model;
We create a model class whose constructor accepts the database table we wish to operate on. We'll be using a single pool for all our models.
We then create a select
method which we will use to retrieve items from our database. This method accepts the columns we want to retrieve and a clause, such as a WHERE
clause. It returns the result of the query, which is a Promise
. Remember we said earlier that every query is executed by a client, but here we execute the query with pool. This is because, when we use pool.query
, node-postgres
executes the query using the first available idle client.
The query you write is entirely up to you, provided it is a valid SQL
statement that can be executed by a Postgres engine.
The next step is to actually create an API endpoint to utilize our newly connected database. Before we do that, I'd like us to create some utility functions. The goal is for us to have a way to perform common database operations from the command line.
Create a folder, utils/
inside the src/
folder. Create three files inside this folder:
- queries.js
- queryFunctions.js
- runQuery.js
We're going to create functions to create a table in our database, insert seed data in the table, and to delete the table.
query.js dosyasını açın ve aşağıdaki kodu yapıştırın:
export const createMessageTable = ` DROP TABLE IF EXISTS messages; CREATE TABLE IF NOT EXISTS messages ( id SERIAL PRIMARY KEY, name VARCHAR DEFAULT '', message VARCHAR NOT NULL ) `; export const insertMessages = ` INSERT INTO messages(name, message) VALUES ('chidimo', 'first message'), ('orji', 'second message') `; export const dropMessagesTable = 'DROP TABLE messages';
Bu dosyada üç adet SQL sorgu dizisi tanımlıyoruz. İlk sorgu, messages
tablosunu siler ve yeniden oluşturur. İkinci sorgu, messages
tablosuna iki satır ekler. Buraya daha fazla öğe eklemekten çekinmeyin. Son sorgu, messages
tablosunu bırakır/siler.
queryFunctions.js dosyasını açın ve aşağıdaki kodu yapıştırın:
import { pool } from '../models/pool'; import { insertMessages, dropMessagesTable, createMessageTable, } from './queries'; export const executeQueryArray = async arr => new Promise(resolve => { const stop = arr.length; arr.forEach(async (q, index) => { await pool.query(q); if (index + 1 === stop) resolve(); }); }); export const dropTables = () => executeQueryArray([ dropMessagesTable ]); export const createTables = () => executeQueryArray([ createMessageTable ]); export const insertIntoTables = () => executeQueryArray([ insertMessages ]);
Burada daha önce tanımladığımız sorguları yürütmek için fonksiyonlar oluşturuyoruz. executeQueryArray
işlevinin bir dizi sorgu yürüttüğünü ve her birinin döngü içinde tamamlanmasını beklediğini unutmayın. (Yine de üretim kodunda böyle bir şey yapmayın). Ardından, yalnızca listedeki son sorguyu yürüttüğümüzde sözümüzü çözeriz. Dizi kullanmamızın nedeni, veritabanımızdaki tablo sayısı arttıkça bu tür sorguların sayısının artmasıdır.
runQuery.js'yi açın ve aşağıdaki kodu yapıştırın:
import { createTables, insertIntoTables } from './queryFunctions'; (async () => { await createTables(); await insertIntoTables(); })();
Bu, tabloyu oluşturmak ve mesajları tabloya eklemek için işlevleri yürüttüğümüz yerdir. Bu dosyayı çalıştırmak için package.json'ımızın scripts
bölümüne bir komut ekleyelim.
"runQuery": "babel-node ./src/utils/runQuery"
Şimdi çalıştırın:
yarn runQuery
Veritabanınızı incelerseniz, mesajlar tablosunun oluşturulduğunu ve messages
tabloya eklendiğini göreceksiniz.
ElephantSQL kullanıyorsanız, veritabanı ayrıntıları sayfasında sol gezinme menüsünden BROWSER
tıklayın. messages
tablosunu seçin ve Execute
tıklayın. Mesajları query.js dosyasından görmelisiniz.
Veritabanımızdan gelen mesajları görüntülemek için bir controller ve route oluşturalım.
Yeni bir denetleyici dosyası src/controllers/messages.js oluşturun ve aşağıdaki kodu yapıştırın:
import Model from '../models/model'; const messagesModel = new Model('messages'); export const messagesPage = async (req, res) => { try { const data = await messagesModel.select('name, message'); res.status(200).json({ messages: data.rows }); } catch (err) { res.status(200).json({ messages: err.stack }); } };
Model
sınıfımızı içe aktarıyoruz ve bu modelin yeni bir örneğini oluşturuyoruz. Bu, veritabanımızdaki messages
tablosunu temsil eder. Daha sonra veritabanımızı sorgulamak için modelin select
yöntemini kullanırız. Aldığımız veriler ( name
ve message
) yanıtta JSON olarak gönderilir.
messagesPage
denetleyicisini bir async
işlevi olarak tanımlıyoruz. node-postgres
sorguları bir söz verdiğinden, bu sorgunun sonucunu await
. Sorgu sırasında bir hata ile karşılaşırsak onu yakalar ve yığını kullanıcıya gösteririz. Hatayı nasıl ele alacağınıza karar vermelisiniz.
Get mesajları uç noktasını src/routes/index.js'ye ekleyin ve içe aktarma satırını güncelleyin.
# update the import line import { indexPage, messagesPage } from '../controllers'; # add the get messages endpoint indexRouter.get('/messages', messagesPage)
https://localhost:3000/v1/messages adresini ziyaret edin ve aşağıda gösterildiği gibi görüntülenen mesajları görmelisiniz.

Şimdi test dosyamızı güncelleyelim. TDD yaparken, genellikle testlerinizi, testi geçmeyi sağlayan kodu uygulamadan önce yazarsınız. Burada tam tersi bir yaklaşım izliyorum çünkü hala veritabanını kurmaya çalışıyoruz.
test/
klasöründe yeni bir dosya, hooks.js oluşturun ve aşağıdaki kodu girin:
import { dropTables, createTables, insertIntoTables, } from '../src/utils/queryFunctions'; before(async () => { await createTables(); await insertIntoTables(); }); after(async () => { await dropTables(); });
Testimiz başladığında, Mocha bu dosyayı bulur ve herhangi bir test dosyasını çalıştırmadan önce çalıştırır. Veritabanını oluşturmak ve içine bazı öğeler eklemek için before
kancayı yürütür. Test dosyaları bundan sonra çalışır. Test bittiğinde, Mocha, veritabanını bıraktığımız after
kancayı çalıştırır. Bu, testlerimizi her çalıştırdığımızda, bunu veritabanımızda temiz ve yeni kayıtlarla yapmamızı sağlar.
Yeni bir test dosyası test/messages.test.js oluşturun ve aşağıdaki kodu ekleyin:
import { expect, server, BASE_URL } from './setup'; describe('Messages', () => { it('get messages page', done => { server .get(`${BASE_URL}/messages`) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.messages).to.be.instanceOf(Array); res.body.messages.forEach(m => { expect(m).to.have.property('name'); expect(m).to.have.property('message'); }); done(); }); }); });
/messages
çağrısının sonucunun bir dizi olduğunu iddia ediyoruz. Her mesaj nesnesi için name
ve message
özelliğine sahip olduğunu iddia ederiz.
Bu bölümdeki son adım, CI dosyalarını güncellemektir.
.travis.yml dosyasına aşağıdaki bölümleri ekleyin:
services: - postgresql addons: postgresql: "10" apt: packages: - postgresql-10 - postgresql-client-10 before_install: - sudo cp /etc/postgresql/{9.6,10}/main/pg_hba.conf - sudo /etc/init.d/postgresql restart
Bu, Travis'e testlerimizi çalıştırmadan önce bir PostgreSQL 10 veritabanını döndürmesi talimatını verir.
before_script
bölümündeki ilk giriş olarak veritabanını oluşturmak için komutu ekleyin:
# add this as the first line in the before_script section - psql -c 'create database testdb;' -U postgres
CONNECTION_STRING
ortam değişkenini Travis'te oluşturun ve aşağıdaki değeri kullanın:
CONNECTION_STRING="postgresql://postgres:postgres@localhost:5432/testdb"
.appveyor.yml dosyasına aşağıdaki bölümleri ekleyin:
before_test: - SET PGUSER=postgres - SET PGPASSWORD=Password12! - PATH=C:\Program Files\PostgreSQL\10\bin\;%PATH% - createdb testdb services: - postgresql101
Appveyor'a bağlantı dizesi ortam değişkenini ekleyin. Aşağıdaki satırı kullanın:
CONNECTION_STRING=postgresql://postgres:Password12!@localhost:5432/testdb
Şimdi değişikliklerinizi yapın ve GitHub'a itin. Testleriniz hem Travis CI hem de AppVeyor'dan geçmelidir.
- Depomdaki ilgili dal 07-connect-postgres.
Not : Umarım sizin açınızdan her şey yolunda gider, ancak herhangi bir nedenle sorun yaşarsanız, kodumu her zaman depoda kontrol edebilirsiniz!
Şimdi veritabanımıza nasıl mesaj ekleyebileceğimizi görelim. Bu adım için, POST
istekleri göndermenin bir yoluna ihtiyacımız olacak. POST
istekleri göndermek için Postman kullanacağım.
TDD rotasına gidelim ve elde etmeyi umduğumuz şeyi yansıtmak için testimizi güncelleyelim.
test/message.test.js dosyasını açın ve aşağıdaki test senaryosunu ekleyin:
it('posts messages', done => { const data = { name: 'some name', message: 'new message' }; server .post(`${BASE_URL}/messages`) .send(data) .expect(200) .end((err, res) => { expect(res.status).to.equal(200); expect(res.body.messages).to.be.instanceOf(Array); res.body.messages.forEach(m => { expect(m).to.have.property('id'); expect(m).to.have.property('name', data.name); expect(m).to.have.property('message', data.message); }); done(); }); });
Bu test, /v1/messages
uç noktasına bir POST isteği yapar ve bir dizinin döndürülmesini bekleriz. Ayrıca dizideki id
, name
ve message
özelliklerini de kontrol ederiz.
Bu vakanın başarısız olduğunu görmek için testlerinizi çalıştırın. Şimdi düzeltelim.
Gönderi istekleri göndermek için sunucunun gönderi yöntemini kullanırız. Ayrıca eklemek istediğimiz ismi ve mesajı da gönderiyoruz. Yanıtın, özellik id
ve sorguyu oluşturan diğer bilgilerle birlikte bir dizi olmasını bekliyoruz. id
, veritabanına bir kaydın eklendiğinin kanıtıdır.
src/models/model.js dosyasını açın ve insert
yöntemini ekleyin:
async insertWithReturn(columns, values) { const query = ` INSERT INTO ${this.table}(${columns}) VALUES (${values}) RETURNING id, ${columns} `; return this.pool.query(query); }
Bu, veritabanına mesaj eklememizi sağlayan yöntemdir. Öğeyi ekledikten sonra id
, name
ve message
döndürür.
src/controllers/messages.js dosyasını açın ve aşağıdaki denetleyiciyi ekleyin:
export const addMessage = async (req, res) => { const { name, message } = req.body; const columns = 'name, message'; const values = `'${name}', '${message}'`; try { const data = await messagesModel.insertWithReturn(columns, values); res.status(200).json({ messages: data.rows }); } catch (err) { res.status(200).json({ messages: err.stack }); } };
Adı ve mesajı almak için istek gövdesini yok ederiz. Ardından, insertWithReturn
yöntemiyle yürüttüğümüz bir SQL sorgu dizesi oluşturmak için değerleri kullanırız.
Aşağıdaki POST
bitiş noktasını /src/routes/index.js'ye ekleyin ve içe aktarma satırınızı güncelleyin.
import { indexPage, messagesPage, addMessage } from '../controllers'; indexRouter.post('/messages', addMessage);
Testlerinizi geçip geçmediklerini görmek için çalıştırın.
Postacı'yı açın ve messages
uç noktasına bir POST
isteği gönderin. Testinizi yeni yaptıysanız, messages
tablosunu yeniden oluşturmak için yarn query
çalıştırmayı unutmayın.
yarn query


Değişikliklerinizi kabul edin ve GitHub'a gönderin. Testleriniz hem Travis'ten hem de AppVeyor'dan geçmelidir. Test kapsamınız birkaç puan düşecek, ama sorun değil.
- Depomdaki ilgili dal, db sonrası 08'dir.
ara katman yazılımı
Ekspres tartışmamız, ara katman yazılımından bahsetmeden tamamlanmayacaktır. Express belgeleri bir ara katman yazılımını şu şekilde tanımlar:
“[...] istek nesnesine (req
), yanıt nesnesine (res
) ve uygulamanın istek-yanıt döngüsündeki sonraki ara katman yazılımı işlevine erişimi olan işlevler. Sonraki ara katman yazılımı işlevi, genelliklenext
adlı bir değişkenle belirtilir.
Bir ara yazılım, kimlik doğrulama, istek gövdesini değiştirme vb. gibi herhangi bir sayıda işlevi gerçekleştirebilir. Ara yazılımı kullanmayla ilgili Express belgelerine bakın.
İstek gövdesini değiştiren basit bir ara katman yazılımı yazacağız. Ara yazılımımız, veri tabanına kaydedilmeden önce gelen mesaja SAYS:
kelimesini ekleyecektir.
Başlamadan önce, elde etmek istediğimiz şeyi yansıtmak için testimizi değiştirelim.
test/messages.test.js dosyasını açın ve posts message
test senaryosundaki son beklenen satırı değiştirin:
it('posts messages', done => { ... expect(m).to.have.property('message', `SAYS: ${data.message}`); # update this line ... });
SAYS:
dizesinin mesaja eklendiğini iddia ediyoruz. Bu test senaryosunun başarısız olduğundan emin olmak için testlerinizi çalıştırın.
Şimdi testi geçmek için kodu yazalım.
src/
klasörü içinde yeni bir middleware/
klasörü oluşturun. Bu klasörün içinde iki dosya oluşturun:
- ara yazılım.js
- index.js
Middleware.js içine aşağıdaki kodu girin:
export const modifyMessage = (req, res, next) => { req.body.message = `SAYS: ${req.body.message}`; next(); };
Burada, istek gövdesindeki mesaja SAYS:
dizesini ekliyoruz. Bunu yaptıktan sonra, istek-yanıt zincirinde yürütmeyi bir sonraki işleve geçirmek için next()
işlevini çağırmalıyız. Her ara katman yazılımı, istek-yanıt döngüsünde yürütmeyi bir sonraki ara katman yazılımına geçirmek için next
işlevi çağırmalıdır.
Aşağıdaki kodu index.js içine girin:
# export everything from the middleware file export * from './middleware';
Bu, /middleware.js dosyasındaki ara katman yazılımını dışa aktarır. Şimdilik, yalnızca modifyMessage
ara katman yazılımına sahibiz.
src/routes/index.js dosyasını açın ve ara yazılımı mesaj sonrası istek-yanıt zincirine ekleyin.
import { modifyMessage } from '../middleware'; indexRouter.post('/messages', modifyMessage, addMessage);
addMessage
fonksiyonunun modifyMessage
fonksiyonundan önce geldiğini görebiliriz. modifyMessage
ara yazılımında next
öğesini çağırarak addMessage
işlevini çağırıyoruz. Bir deneme olarak, modifyMessage
ortasındaki next()
satırına yorum yapın ve isteğin askıda kalmasını izleyin.
Postacı'yı açın ve yeni bir mesaj oluşturun. Eklenen dizeyi görmelisiniz.

Bu, değişikliklerimizi taahhüt etmek için iyi bir nokta.
- Depomdaki ilgili dal 09-ara katman yazılımıdır.
Hata İşleme ve Asenkron Ara Yazılım
Herhangi bir uygulamada hatalar kaçınılmazdır. Geliştiricinin önündeki görev, hatalarla mümkün olduğunca zarif bir şekilde nasıl başa çıkılacağıdır.
Ekspres olarak:
“ Hata İşleme , Express'in hem eşzamanlı hem de eşzamansız olarak oluşan hataları nasıl yakalayıp işlediğini ifade eder.
Yalnızca eşzamanlı işlevler yazıyor olsaydık, hata işleme konusunda çok fazla endişelenmemiz gerekmeyebilirdi çünkü Express bunları işleme konusunda zaten mükemmel bir iş çıkarıyor. Belgelere göre:
"Rota işleyicileri ve ara katman yazılımı içindeki eşzamanlı kodda meydana gelen hatalar ekstra çalışma gerektirmez."
Ancak bir kez asenkron yönlendirici işleyicileri ve ara katman yazılımı yazmaya başladığımızda, bazı hata işlemeleri yapmamız gerekir.
modifyMessage
ara yazılımımız senkron bir fonksiyondur. Bu işlevde bir hata oluşursa, Express bunu gayet iyi halledecektir. Asenkron ara katman yazılımındaki hatalarla nasıl başa çıktığımızı görelim.
Diyelim ki bir mesaj oluşturmadan önce bu URL https://picsum.photos/id/0/info
kullanarak Lorem Picsum API'sinden bir resim almak istiyoruz. Bu, başarılı veya başarısız olabilen eşzamansız bir işlemdir ve başa çıkmamız gereken bir durum sunar.
Axios'u yükleyerek başlayın.
# install axios yarn add axios
src/middleware/middleware.js dosyasını açın ve aşağıdaki işlevi ekleyin:
export const performAsyncAction = async (req, res, next) => { try { await axios.get('https://picsum.photos/id/0/info'); next(); } catch (err) { next(err); } };
Bu zaman async
işlevde, bir API'ye bir çağrı await
(aslında döndürülen verilere ihtiyacımız yoktur) ve ardından istek zincirindeki next
işlevi çağırırız. İstek başarısız olursa, hatayı yakalar ve next
. Express bu hatayı gördüğünde, zincirdeki diğer tüm ara katman yazılımlarını atlar. next(err)
, istek askıda kalacak. err
olmadan sadece next()
öğesini çağırırsak, istek hiçbir şey olmamış gibi devam edecek ve hata yakalanmayacaktır.
Bu işlevi içe aktarın ve mesaj sonrası yolunun ara katman zincirine ekleyin:
import { modifyMessage, performAsyncAction } from '../middleware'; indexRouter.post('/messages', modifyMessage, performAsyncAction, addMessage);
src/app.js dosyasını açın ve export default app
satırının hemen öncesine aşağıdaki kodu ekleyin.
app.use((err, req, res, next) => { res.status(400).json({ error: err.stack }); }); export default app;
Bu bizim hata işleyicimiz. Express hata işleme belgesine göre:
"[...] hata işleme işlevlerinin üç yerine dört bağımsız değişkeni vardır: (err, req, res, next)
."
Her app.use()
çağrısından sonra bu hata işleyicinin en son gelmesi gerektiğini unutmayın. Bir hatayla karşılaştığımızda, yığın izini 400
durum koduyla döndürürüz. Hata ile ne istersen yapabilirsin. Günlüğe kaydetmek veya bir yere göndermek isteyebilirsiniz.
Bu, değişikliklerinizi taahhüt etmek için iyi bir yerdir.
- Depomdaki ilgili dal 10-async-ara yazılımdır.
Heroku'ya Dağıt
- Başlamak için https://www.heroku.com/ adresine gidin ve oturum açın veya kaydolun.
- Heroku CLI'yi buradan indirin ve kurun.
- Komutu çalıştırmak için proje klasöründe bir terminal açın.
# login to heroku on command line heroku login
Bu, bir tarayıcı penceresi açacak ve sizden Heroku hesabınıza giriş yapmanızı isteyecektir.
Heroku hesabınıza terminal erişimi vermek için oturum açın ve aşağıdakileri çalıştırarak yeni bir heroku uygulaması oluşturun:
#app name is up to you heroku create app-name
Bu, uygulamayı Heroku'da oluşturacak ve iki URL döndürecektir.
# app production url and git url https://app-name.herokuapp.com/ | https://git.heroku.com/app-name.git
Sağdaki URL'yi kopyalayın ve aşağıdaki komutu çalıştırın. Heroku'nun uzak URL'yi zaten eklediğini görebileceğiniz için bu adımın isteğe bağlı olduğunu unutmayın.
# add heroku remote url git remote add heroku https://git.heroku.com/my-shiny-new-app.git
Bir yan terminal açın ve aşağıdaki komutu çalıştırın. Bu, uygulama günlüğünü resimde gösterildiği gibi gerçek zamanlı olarak gösterir.
# see process logs heroku logs --tail

Gerekli ortam değişkenlerini ayarlamak için aşağıdaki üç komutu çalıştırın:
heroku config:set TEST_ENV_VARIABLE="Environment variable is coming across." heroku config:set CONNECTION_STRING=your-db-connection-string-here. heroku config:set NPM_CONFIG_PRODUCTION=false
Komut dosyalarımızda şunları belirlediğimizi unutmayın:
"prestart": "babel ./src --out-dir build", "start": "node ./build/bin/www",
Uygulamayı başlatmak için, başlatma öncesi adımda babel kullanılarak prestart
kadar derlenmesi gerekir çünkü babel yalnızca geliştirme bağımlılıklarımızda bulunur. Bunları da yükleyebilmek için NPM_CONFIG_PRODUCTION
false
olarak ayarlamalıyız.
Her şeyin doğru ayarlandığını onaylamak için aşağıdaki komutu çalıştırın. Ayrıca uygulama sayfasındaki settings
sekmesini ziyaret edebilir ve Reveal Config Vars
seçeneğine tıklayabilirsiniz.
# check configuration variables heroku config
Şimdi git push heroku
çalıştırın.
Uygulamayı açmak için şunu çalıştırın:
# open /v1 route heroku open /v1 # open /v1/messages route heroku open /v1/messages
Benden hoşlanıyorsanız, hem geliştirme hem de üretim için aynı PostgresSQL veritabanını kullanıyorsanız, testlerinizi her çalıştırdığınızda veritabanının silindiğini görebilirsiniz. Yeniden oluşturmak için aşağıdaki komutlardan birini çalıştırabilirsiniz:
# run script locally yarn runQuery # run script with heroku heroku run yarn runQuery
Travis ile Sürekli Dağıtım (CD)
Şimdi CI/CD akışını tamamlamak için Sürekli Dağıtımı (CD) ekleyelim. Her başarılı test çalışmasından sonra Travis'ten konuşlandıracağız.
İlk adım Travis CI'yi kurmaktır. (Kurulum talimatlarını burada bulabilirsiniz.) Travis CI'yi başarıyla kurduktan sonra, aşağıdaki komutu çalıştırarak oturum açın. (Bunun proje deponuzda yapılması gerektiğini unutmayın.)
# login to travis travis login --pro # use this if you're using two factor authentication travis login --pro --github-token enter-github-token-here
Projeniz travis-ci.org'da barındırılıyorsa --pro
bayrağını kaldırın. GitHub belirteci almak için hesabınızın geliştirici ayarları sayfasını ziyaret edin ve bir tane oluşturun. Bu, yalnızca hesabınız 2FA ile güvence altına alınmışsa geçerlidir.
.travis.yml dosyanızı açın ve bir dağıtım bölümü ekleyin:
deploy: provider: heroku app: master: app-name
Burada Heroku'ya dağıtım yapmak istediğimizi belirtiyoruz. Uygulama alt bölümü, depomuzun master
dalını Heroku'daki uygulama app-name
uygulamasına dağıtmak istediğimizi belirtir. Farklı uygulamalara farklı dallar dağıtmak mümkündür. Mevcut seçenekler hakkında daha fazla bilgiyi buradan okuyabilirsiniz.
Heroku API anahtarınızı şifrelemek için aşağıdaki komutu çalıştırın ve dağıtım bölümüne ekleyin:
# encrypt heroku API key and add to .travis.yml travis encrypt $(heroku auth:token) --add deploy.api_key --pro
Bu, dağıtım bölümüne aşağıdaki alt bölümü ekleyecektir.
api_key: secure: very-long-encrypted-api-key-string
Şimdi değişikliklerinizi gerçekleştirin ve günlüklerinizi izlerken GitHub'a aktarın. Travis testi yapılır yapılmaz yapının tetiklendiğini göreceksiniz. Bu şekilde, başarısız bir testimiz olursa, değişiklikler asla dağıtılmaz. Benzer şekilde, derleme başarısız olursa, tüm test çalıştırması başarısız olur. Bu, CI/CD akışını tamamlar.
- Depomdaki ilgili dal 11-cd'dir.
Çözüm
Buraya kadar geldiyseniz, "Yaşasın!" derim. Bu eğitimde, yeni bir Express projesini başarıyla kurduk. Sürekli Entegrasyon (CI) yanı sıra geliştirme bağımlılıklarını yapılandırmaya devam ettik. Ardından, API uç noktalarımıza gelen istekleri işlemek için eşzamansız işlevler yazdık ve testler tamamlandı. Daha sonra kısaca hata işlemeye baktık. Son olarak projemizi Heroku'ya dağıttık ve Sürekli Dağıtımı yapılandırdık.
Artık bir sonraki arka uç projeniz için bir şablonunuz var. Başlamanız için yeterince şey yaptık, ancak devam etmeyi öğrenmeye devam etmelisiniz. Express.js belgelerini de kontrol ettiğinizden emin olun. PostgreSQL
yerine MongoDB
kullanmayı tercih ederseniz, burada tam olarak bunu yapan bir şablonum var. Kurulum için inceleyebilirsiniz. Sadece birkaç nokta farkı var.
Kaynaklar
- Orji Chidi Matthew, GitHub "MongoDB ile Express API Arka Uç Oluşturun"
- Stephen Sugden, "Ara Katman Yazılımını Bağlamak İçin Kısa Bir Kılavuz"
- "Express API şablonu" GitHub
- "AppVeyor ve Travis CI," StackShare
- "Heroku CLI," Heroku Geliştirme Merkezi
- “Heroku Dağıtımı,” Travis CI
- “Ara katman yazılımı kullanma,” Express.js
- "Hata İşleme", Express.js
- “Başlarken,” Mocha
-
nyc
(GitHub) - ElephantSQL
- postacı
- ifade etmek
- Travis CI
- Kod İklim
- PostgreSQL
- pgAdmin