Düğümle Başlayın: API'lere Giriş, HTTP ve ES6+ JavaScript
Yayınlanan: 2022-03-10Node.js'nin "Chrome'un V8 JavaScript motoru üzerine kurulu eşzamansız bir JavaScript çalışma zamanı" olduğunu ve "onu hafif ve verimli kılan olaya dayalı, engellemeyen bir G/Ç modeli kullandığını" muhtemelen duymuşsunuzdur. Ancak bazıları için bu, açıklamaların en büyüğü değildir.
İlk etapta Düğüm nedir? Düğüm için "eşzamansız" olmak tam olarak ne anlama gelir ve bunun "eşzamanlı"dan farkı nedir? Zaten "olay güdümlü" ve "engellenmeyen" anlamı nedir ve Node, uygulamaların, İnternet ağlarının ve sunucuların daha büyük resmine nasıl sığar?
Düğümün iç işleyişine derinlemesine bir göz atarken, Köprü Metni Aktarım Protokolü, API'ler ve JSON hakkında bilgi edinirken ve kullanarak kendi Bookshelf API'mizi oluştururken bu seri boyunca tüm bu soruları ve daha fazlasını yanıtlamaya çalışacağız. MongoDB, Express, Lodash, Mocha ve Gidonlar.
Node.js Nedir?
Düğüm, yalnızca tarayıcı dışında normal JavaScript'in (küçük farklılıklarla) çalıştırılacağı bir ortam veya çalışma zamanıdır. Masaüstü uygulamaları (Electron gibi çerçeveler ile), web veya uygulama sunucuları yazmak ve daha fazlası için kullanabiliriz.
Engelleme/Engellemesiz ve Senkron/Eşzamansız
Bir kullanıcı hakkındaki özellikleri almak için bir veritabanı çağrısı yaptığımızı varsayalım. Bu çağrı zaman alacak ve eğer istek "engelleniyorsa", bu, çağrı tamamlanana kadar programımızın yürütülmesini engelleyeceği anlamına gelir. Bu durumda, iş parçacığını engellediği için “senkronize” bir istekte bulunduk.
Bu nedenle, senkronize bir işlem, bir işlemi veya iş parçacığını bu işlem tamamlanana kadar engeller ve iş parçacığını "bekleme durumunda" bırakır. Öte yandan, eşzamansız bir işlem engellemesizdir . İşlemin tamamlanması için geçen süreye veya sonuçla sonuçlanmasına bakılmaksızın iş parçacığının yürütülmesine izin verir ve iş parçacığının hiçbir parçası herhangi bir noktada bekleme durumuna düşmez.
Bir iş parçacığını engelleyen başka bir eşzamanlı çağrı örneğine bakalım. Sıcaklıktaki yüzde farklarını bulmak için iki Hava Durumu API'sinin sonuçlarını karşılaştıran bir uygulama oluşturduğumuzu varsayalım. Engelleyici bir şekilde Weather API One'a bir çağrı yapıyoruz ve sonucu bekliyoruz. Bir sonuç aldığımızda, Weather API Two'yu çağırır ve sonucunu bekleriz. API'lere aşina değilseniz bu noktada endişelenmeyin. Onları gelecek bir bölümde ele alacağız. Şimdilik, bir API'yi iki bilgisayarın birbiriyle iletişim kurabileceği ortam olarak düşünün.
Şunu belirtmeme izin verin, tüm eşzamanlı aramaların mutlaka engellemediğini bilmek önemlidir. Eşzamanlı bir işlem, iş parçacığını engellemeden veya bir bekleme durumuna neden olmadan tamamlamayı başarabiliyorsa, engelleme yapmıyordu. Çoğu zaman, eşzamanlı çağrılar engellenir ve tamamlanmaları için gereken süre, API sunucularının hızı, son kullanıcının internet bağlantısı indirme hızı vb. gibi çeşitli faktörlere bağlı olacaktır.
Yukarıdaki resim durumunda, API One'dan ilk sonuçları almak için epey bir süre beklememiz gerekti. Bundan sonra, API Two'dan bir yanıt almak için eşit derecede beklememiz gerekti. Her iki yanıtı da beklerken, kullanıcı uygulamamızın askıda kaldığını fark eder - UI kelimenin tam anlamıyla kilitlenir - ve bu, Kullanıcı Deneyimi için kötü olur.
Engellemeyen bir çağrı olması durumunda, şöyle bir şeyimiz olur:
Yürütmeyi ne kadar hızlı sonuçlandırdığımızı açıkça görebilirsiniz. API One'da beklemek ve ardından API Two'da beklemek yerine, her ikisinin de aynı anda tamamlanmasını ve sonuçlarımıza neredeyse %50 daha hızlı ulaşmasını bekleyebilirdik. Dikkat edin, API One'ı arayıp yanıtını beklemeye başladığımızda, API Two'yu da aradık ve One ile aynı anda yanıtını beklemeye başladık.
Bu noktada, daha somut ve somut örneklere geçmeden önce, kolaylık olması açısından “Senkron” teriminin genellikle “Senkron” olarak kısaltıldığını ve “Asenkron” teriminin genellikle “Async” olarak kısaltıldığını belirtmek önemlidir. Yöntem/fonksiyon adlarında kullanılan bu gösterimi göreceksiniz.
Geri Arama Fonksiyonları
"Bir aramayı eşzamansız olarak halledebilirsek, bu aramanın ne zaman bittiğini ve bir yanıtımız olduğunu nasıl bilebiliriz?" Diye merak ediyor olabilirsiniz. Genel olarak, async yöntemimize bir argüman olarak bir geri arama işlevi iletiriz ve bu yöntem daha sonra bir yanıtla bu işlevi "geri arayacaktır". Burada ES5 işlevlerini kullanıyorum, ancak daha sonra ES6 standartlarına güncelleyeceğiz.
function asyncAddFunction(a, b, callback) { callback(a + b); //This callback is the one passed in to the function call below. } asyncAddFunction(2, 4, function(sum) { //Here we have the sum, 2 + 4 = 6. });
Böyle bir fonksiyon, argüman olarak bir fonksiyon (bizim geri çağrımız) aldığı için “Yüksek Dereceli Fonksiyon” olarak adlandırılır. Alternatif olarak, bir geri çağırma işlevi, bir hata nesnesini ve bir yanıt nesnesini bağımsız değişken olarak alabilir ve bunları zaman uyumsuz işlev tamamlandığında sunabilir. Bunu daha sonra Express ile göreceğiz. asyncAddFunction(...)
, yöntem tanımından geri çağırma parametresi için bir geri çağırma işlevi sağladığımızı fark edeceksiniz. Bu işlev anonim bir işlevdir (bir adı yoktur) ve İfade Sözdizimi kullanılarak yazılır. Yöntem tanımı ise bir fonksiyon ifadesidir. Anonim değildir çünkü aslında bir adı vardır ("asyncAddFunction" olan).
Bazıları, yöntem tanımında "geri arama" olan bir ad verdiğimiz için karışıklık olduğunu fark edebilir. Ancak, asyncAddFunction(...)
üçüncü parametre olarak iletilen anonim işlev adı bilmez ve bu nedenle adsız kalır. Ayrıca bu işlevi daha sonraki bir noktada ada göre yürütemeyiz, ateşlemek için tekrar zaman uyumsuz çağrı işlevinden geçmemiz gerekir.
Eşzamanlı çağrıya örnek olarak Node.js readFileSync(...)
yöntemini kullanabiliriz. Yine, daha sonra ES6+'ya geçeceğiz.
var fs = require('fs'); var data = fs.readFileSync('/example.txt'); // The thread will be blocked here until complete.
Bunu eşzamansız olarak yapıyor olsaydık, eşzamansız işlem tamamlandığında tetiklenecek bir geri çağırma işlevine geçerdik.
var fs = require('fs'); var data = fs.readFile('/example.txt', function(err, data) { //Move on, this will fire when ready. if(err) return console.log('Error: ', err); console.log('Data: ', data); // Assume var data is defined above. }); // Keep executing below, don't wait on the data.
Daha önce return
bu şekilde kullanıldığını görmediyseniz, sadece fonksiyon yürütmeyi durdurmanızı söylüyoruz, böylece hata nesnesi tanımlanmışsa veri nesnesini yazdırmayız. Ayrıca log ifadesini else
bir yan tümceye sarabilirdik.
asyncAddFunction(...)
gibi, fs.readFile(...)
işlevinin arkasındaki kod şu satırlar boyunca bir şey olacaktır:
function readFile(path, callback) { // Behind the scenes code to read a file stream. // The data variable is defined up here. callback(undefined, data); //Or, callback(err, undefined); }
Bir zaman uyumsuz işlev çağrısının son bir uygulamasına bakmamıza izin verin. Bu, geri çağırma işlevlerinin daha sonraki bir zamanda tetiklenmesi fikrini sağlamlaştırmaya yardımcı olacak ve tipik bir Node.js programının yürütülmesini anlamamıza yardımcı olacaktır.
setTimeout(function() { // ... }, 1000);
setTimeout(...)
yöntemi, ikinci argüman olarak belirtilen milisaniye sayısı gerçekleştikten sonra tetiklenecek olan ilk parametre için bir geri çağırma işlevi alır.
Daha karmaşık bir örneğe bakalım:
console.log('Initiated program.'); setTimeout(function() { console.log('3000 ms (3 sec) have passed.'); }, 3000); setTimeout(function() { console.log('0 ms (0 sec) have passed.'); }, 0); setTimeout(function() { console.log('1000 ms (1 sec) has passed.'); }, 1000); console.log('Terminated program');
Aldığımız çıktı:
Initiated program. Terminated program. 0 ms (0 sec) have passed. 1000 ms (1 sec) has passed. 3000 ms (3 sec) have passed.
İlk günlük ifadesinin beklendiği gibi çalıştığını görebilirsiniz. Anında, son günlük ifadesi ekrana yazdırılır, çünkü bu, ikinci setTimeout(...)
dan sonra 0 saniye aşılmadan önce olur. Hemen ardından ikinci, üçüncü ve birinci setTimeout(...)
yöntemleri yürütülür.
Node.js engelleyici olmasaydı, ilk günlük ifadesini görürdük, sonrakini görmek için 3 saniye beklerdik, anında üçüncüyü görürdük (0 saniyelik setTimeout(...)
ve sonra bir tane daha beklememiz gerekirdi. son iki günlük ifadesini görmek için saniye. Node'un engelleyici olmayan doğası, tüm zamanlayıcıların yazıldığı sıra yerine programın yürütüldüğü andan itibaren geri saymaya başlamasını sağlar. Node'un başlık altında nasıl çalıştığı hakkında daha fazla bilgi için Callstack ve Event Loop.
Bir geri arama işlevi görmenizin, kodda eşzamansız bir arama olduğu anlamına gelmediğini unutmamak önemlidir. Bir sunucuya çağrı yapmak gibi işlemin tamamlanmasının zaman alacağını varsaydığımız için asyncAddFunction(…)
yöntemini “async”in üzerinde çağırdık. Gerçekte, iki sayı ekleme işlemi zaman uyumsuz değildir ve bu nedenle, aslında iş parçacığını engellemeyen bir şekilde bir geri arama işlevi kullanmanın bir örneği olacaktır.
Geri Aramalar Üzerinden Vaatler
JavaScript'te geri aramalar, özellikle birden çok iç içe geçmiş geri aramalar hızla dağınık hale gelebilir. Bir işleve argüman olarak bir geri arama iletmeye aşinayız, ancak Sözler, bir işlevden döndürülen bir nesneye bir geri arama eklememize veya eklememize izin verir. Bu, birden çok zaman uyumsuz çağrıyı daha zarif bir şekilde ele almamızı sağlar.
Örnek olarak, bir API çağrısı yaptığımızı ve benzersiz olarak adlandırılan ' makeAPICall(...)
' olmayan işlevimizin bir URL ve bir geri arama aldığını varsayalım.
Fonksiyonumuz makeAPICall(...)
şu şekilde tanımlanır:
function makeAPICall(path, callback) { // Attempt to make API call to path argument. // ... callback(undefined, res); // Or, callback(err, undefined); depending upon the API's response. }
ve biz onu şöyle çağırırdık:
makeAPICall('/example', function(err1, res1) { if(err1) return console.log('Error: ', err1); // ... });
İlkinden gelen yanıtı kullanarak başka bir API çağrısı yapmak istersek, her iki geri çağrıyı da iç içe geçirmemiz gerekir. res1
nesnesinden userName
özelliğini ikinci API çağrısının yoluna enjekte etmem gerektiğini varsayalım. Şunları yapardık:
makeAPICall('/example', function(err1, res1) { if(err1) return console.log('Error: ', err1); makeAPICall('/newExample/' + res1.userName, function(err2, res2) { if(err2) return console.log('Error: ', err2); console.log(res2); }); });
Not : Dize birleştirme yerine res1.userName
özelliğini enjekte etmek için ES6+ yöntemi "Şablon Dizeleri" kullanmak olacaktır. Bu şekilde, dizgimizi tırnak işaretleri ( '
veya "
) içine almak yerine, klavyenizdeki Escape tuşunun altında bulunan ters tırnakları ( `
) kullanırdık. Ardından, herhangi bir JS ifadesini gömmek için ${}
gösterimini kullanırdık. Sonunda, önceki yolumuz şu olurdu: /newExample/${res.UserName}
, geri tepmelere sarılmış.
Bu iç içe geri arama yönteminin, “JavaScript Doom Piramidi” olarak adlandırılan, hızla oldukça yetersiz hale gelebileceğini görmek açıktır. Geri aramalar yerine sözler kullanıyor olsaydık, ilk örnekteki kodumuzu şu şekilde yeniden düzenleyebilirdik:
makeAPICall('/example').then(function(res) { // Success callback. // ... }, function(err) { // Failure callback. console.log('Error:', err); });
Then then()
işlevinin ilk argümanı bizim başarılı geri aramamız, ikinci argüman ise başarısızlık geri aramamızdır. Alternatif olarak, .then( .then()
için ikinci argümanı kaybedebilir ve bunun yerine .catch()
çağırabiliriz. .then( .then()
ile ilgili argümanlar isteğe bağlıdır ve .catch() öğesinin çağrılması .catch()
.then(successCallback, null)
eşdeğer olacaktır.
.catch()
kullanarak şunları elde ederiz:
makeAPICall('/example').then(function(res) { // Success callback. // ... }).catch(function(err) { // Failure Callback console.log('Error: ', err); });
Bunu ayrıca okunabilirlik için yeniden yapılandırabiliriz:
makeAPICall('/example') .then(function(res) { // ... }) .catch(function(err) { console.log('Error: ', err); });
Herhangi bir fonksiyona sadece bir .then()
çağrısını bağlayamayacağımızı ve çalışmasını bekleyemeyeceğimizi not etmek önemlidir. Çağırdığımız işlevin aslında bir söz vermesi gerekiyor, bu zaman uyumsuz işlem tamamlandığında .then()
'i tetikleyecek bir söz. Bu durumda makeAPICall(...)
, tamamlandığında ya then()
bloğunu ya da catch()
bloğunu ateşler.
makeAPICall(...)
bir Promise döndürmesini sağlamak için, bir değişkene bir işlev atarız, burada bu işlev Promise yapıcısıdır. Sözler yerine getirilebilir veya reddedilebilir , burada yerine getirildi, sözle ilgili eylemin başarıyla tamamlandığı ve reddedildiği anlamına gelir. Söz bir kez yerine getirildikten veya reddedildikten sonra, yerine getirildi deriz ve yerleşmesini beklerken, belki bir zaman uyumsuz çağrı sırasında, sözün beklemede olduğunu söyleriz.
Promise yapıcısı, argüman olarak bir geri çağırma işlevini alır ve bu iki parametreyi alır: .then()
içindeki başarılı geri aramayı veya .then()
başarısızlığını başlatmak için daha sonraki bir noktada çağrılacak resolve
ve reject
. geri arama veya .catch()
.
İşte bunun nasıl göründüğüne bir örnek:
var examplePromise = new Promise(function(resolve, reject) { // Do whatever we are going to do and then make the appropiate call below: resolve('Happy!'); // — Everything worked. reject('Sad!'); // — We noticed that something went wrong. }):
Ardından şunları kullanabiliriz:
examplePromise.then(/* Both callback functions in here */); // Or, the success callback in .then() and the failure callback in .catch().
Ancak, examplePromise
herhangi bir argüman alamayacağına dikkat edin. Bu tür bir amacı bozar, bu yüzden onun yerine bir söz verebiliriz.
function makeAPICall(path) { return new Promise(function(resolve, reject) { // Make our async API call here. if (/* All is good */) return resolve(res); //res is the response, would be defined above. else return reject(err); //err is error, would be defined above. }); }
Sözler, “Söz Zincirleme” konsepti ile kodumuzun yapısını ve ardından zarafetini geliştirmek için gerçekten parlıyor. Bu, bir .then()
yan tümcesi içinde yeni bir Promise döndürmemize izin verir, böylece ikinci bir .then()
ekleyebiliriz, bu da ikinci sözden uygun geri aramayı tetikler.
Yukarıdaki çoklu API URL çağrımızı Promises ile yeniden düzenlersek şunları elde ederiz:
makeAPICall('/example').then(function(res) { // First response callback. Fires on success to '/example' call. return makeAPICall(`/newExample/${res.UserName}`); // Returning new call allows for Promise Chaining. }, function(err) { // First failure callback. Fires if there is a failure calling with '/example'. console.log('Error:', err); }).then(function(res) { // Second response callback. Fires on success to returned '/newExample/...' call. console.log(res); }, function(err) { // Second failure callback. Fire if there is a failure calling with '/newExample/...' console.log('Error:', err); });
İlk önce makeAPICall('/example')
adlandırdığımıza dikkat edin. Bu bir söz verir ve böylece bir .then()
. Bunun içinde then()
, makeAPICall(...)
yeni bir çağrı döndürürüz; bu çağrı, daha önce görüldüğü gibi, kendi başına bir söz verir ve ilkinden sonra yeni bir .then( .then()
üzerinde zincirlememize izin verir.
Yukarıdaki gibi, bunu okunabilirlik için yeniden yapılandırabilir ve genel bir catch()
all yan tümcesi için başarısızlık geri çağrılarını kaldırabiliriz. Ardından DRY İlkesini (Kendinizi Tekrar Etmeyin) uygulayabiliriz ve yalnızca bir kez hata işlemeyi uygulamamız gerekir.
makeAPICall('/example') .then(function(res) { // Like earlier, fires with success and response from '/example'. return makeAPICall(`/newExample/${res.UserName}`); // Returning here lets us chain on a new .then(). }) .then(function(res) { // Like earlier, fires with success and response from '/newExample'. console.log(res); }) .catch(function(err) { // Generic catch all method. Fires if there is an err with either earlier call. console.log('Error: ', err); });
.then()
içindeki başarı ve başarısızlık geri aramalarının yalnızca .then()
'in karşılık geldiği bireysel Sözün durumu için tetiklendiğini unutmayın. Ancak catch
bloğu, .then()
lerin herhangi birinde tetiklenen hataları yakalayacaktır.
ES6 Const vs Let
Tüm örneklerimizde ES5 fonksiyonlarını ve eski var
anahtar sözcüğünü kullandık. Milyonlarca satır kod bugün hala bu ES5 yöntemlerini kullanarak çalışıyor olsa da, mevcut ES6+ standartlarına güncelleme yapmak yararlıdır ve yukarıdaki kodlarımızdan bazılarını yeniden gözden geçireceğiz. const
ile başlayalım ve let
.
var
anahtar sözcüğüyle bir değişken bildirmek için kullanılmış olabilirsiniz:
var pi = 3.14;
ES6+ standartlarıyla bunu da yapabiliriz
let pi = 3.14;
veya
const pi = 3.14;
const
"sabit" anlamına gelir - daha sonra yeniden atanamayan bir değer. (Nesne özellikleri dışında - bunu yakında ele alacağız. Ayrıca, const
olarak bildirilen değişkenler değişmez değildir , yalnızca değişkene yapılan başvurudur.)
Eski JavaScript'te, if
, while
, {}
içindekiler gibi kapsamları engelleyin. for
, vb. var
hiçbir şekilde etkilemedi ve bu, Java veya C++ gibi statik olarak yazılan dillerden oldukça farklıdır. Diğer bir deyişle, var
kapsamı, çevreleyen işlevin tamamıdır ve bu, global (bir işlevin dışına yerleştirilmişse) veya yerel (bir işlevin içine yerleştirilmişse) olabilir. Bunu göstermek için aşağıdaki örneğe bakın:
function myFunction() { var num = 5; console.log(num); // 5 console.log('--'); for(var i = 0; i < 10; i++) { var num = i; console.log(num); //num becomes 0 — 9 } console.log('--'); console.log(num); // 9 console.log(i); // 10 } myFunction();
Çıktı:
5 --- 0 1 2 3 ... 7 8 9 --- 9 10
Burada dikkat edilmesi gereken önemli nokta, for
kapsamı içinde yeni bir var num
tanımlamanın for
öğesinin dışındaki ve üstündeki var num
doğrudan etkilediğidir. Bunun nedeni, var
kapsamının her zaman bir blok değil, çevreleyen işlevin kapsamı olmasıdır.
Yine, varsayılan olarak, var i
inside for()
varsayılan olarak myFunction
'ın kapsamına geçer ve böylece i
döngü dışından erişebilir ve 10 elde edebiliriz.
Değişkenlere değer atama açısından, let
is eşdeğer var
, sadece let
blok kapsamına sahiptir ve bu nedenle yukarıda var
ile meydana gelen anormallikler gerçekleşmeyecektir.
function myFunction() { let num = 5; console.log(num); // 5 for(let i = 0; i < 10; i++) { let num = i; console.log('--'); console.log(num); // num becomes 0 — 9 } console.log('--'); console.log(num); // 5 console.log(i); // undefined, ReferenceError }
const
anahtar kelimesine baktığımızda, ona yeniden atamaya çalışırsak bir hata aldığımızı görebilirsiniz:
const c = 299792458; // Fact: The constant "c" is the speed of light in a vacuum in meters per second. c = 10; // TypeError: Assignment to constant variable.
Bir nesneye bir const
değişkeni atadığımızda işler ilginç hale gelir:
const myObject = { name: 'Jane Doe' }; // This is illegal: TypeError: Assignment to constant variable. myObject = { name: 'John Doe' }; // This is legal. console.log(myObject.name) -> John Doe myObject.name = 'John Doe';
Gördüğünüz gibi, bir const
nesnesine atanan nesneye yalnızca bellekte yapılan başvuru değişmezdir, öz değeri değil.
ES6 Ok İşlevleri
Bunun gibi bir işlev oluşturmaya alışmış olabilirsiniz:
function printHelloWorld() { console.log('Hello, World!'); }
Ok işlevleriyle bu şöyle olur:
const printHelloWorld = () => { console.log('Hello, World!'); };
Bir sayının karesini döndüren basit bir fonksiyonumuz olduğunu varsayalım:
const squareNumber = (x) => { return x * x; } squareNumber(5); // We can call an arrow function like an ES5 functions. Returns 25.
Görüyorsunuz, tıpkı ES5 işlevlerinde olduğu gibi, parantezli argümanlar alabiliyoruz, normal dönüş deyimlerini kullanabiliriz ve tıpkı diğerleri gibi işlevi çağırabiliriz.
Unutulmamalıdır ki, fonksiyonumuz hiçbir argüman almıyorsa (yukarıdaki printHelloWorld()
ile olduğu gibi) parantezler gerekli olsa da, sadece bir tane alırsa parantezleri bırakabiliriz, bu nedenle önceki squareNumber()
yöntem tanımımız şu şekilde yeniden yazılabilir:
const squareNumber = x => { // Notice we have dropped the parentheses for we only take in one argument. return x * x; }
Tek bir argümanı parantez içine alıp almamak kişisel zevk meselesidir ve muhtemelen geliştiricilerin her iki yöntemi de kullandığını göreceksiniz.
Son olarak, yukarıdaki squareNumber(...)
ile olduğu gibi yalnızca bir ifadeyi örtük olarak döndürmek istiyorsak, return ifadesini yöntem imzasıyla aynı hizaya getirebiliriz:
const squareNumber = x => x * x;
Yani,
const test = (a, b, c) => expression
aynıdır
const test = (a, b, c) => { return expression }
Bir nesneyi dolaylı olarak döndürmek için yukarıdaki stenografiyi kullanırken, işler belirsiz hale gelir. JavaScript'in nesnemizi içine almamız gereken parantezlerin işlev gövdemiz olmadığına inanmasını engelleyen nedir? Bunu aşmak için nesnenin parantezlerini parantez içine alırız. Bu, JavaScript'in gerçekten bir nesne döndürdüğümüzü ve yalnızca bir gövde tanımlamadığımızı bilmesini sağlar.
const test = () => ({ pi: 3.14 }); // Spaces between brackets are a formality to make the code look cleaner.
ES6 işlevleri kavramını sağlamlaştırmaya yardımcı olmak için, önceki kodlarımızdan bazılarını yeniden düzenleyerek her iki gösterim arasındaki farkları karşılaştırmamıza izin vereceğiz.
asyncAddFunction(...)
, yukarıdan yeniden düzenlenebilir:
function asyncAddFunction(a, b, callback){ callback(a + b); }
ile:
const aysncAddFunction = (a, b, callback) => { callback(a + b); };
hatta:
const aysncAddFunction = (a, b, callback) => callback(a + b); // This will return callback(a + b).
İşlevi çağırırken, geri arama için bir ok işlevi iletebiliriz:
asyncAddFunction(10, 12, sum => { // No parentheses because we only take one argument. console.log(sum); }
Bu yöntemin kod okunabilirliğini nasıl geliştirdiğini görmek açıktır. Size sadece bir vakayı göstermek için yukarıdaki eski ES5 Promise tabanlı örneğimizi alabilir ve ok fonksiyonlarını kullanacak şekilde yeniden düzenleyebiliriz.
makeAPICall('/example') .then(res => makeAPICall(`/newExample/${res.UserName}`)) .then(res => console.log(res)) .catch(err => console.log('Error: ', err));
Şimdi, ok işlevleriyle ilgili bazı uyarılar var. Birincisi, this
anahtar sözcüğünü bağlamazlar. Aşağıdaki nesneye sahip olduğumu varsayalım:
const Person = { name: 'John Doe', greeting: () => { console.log(`Hi. My name is ${this.name}.`); } }
Person.greeting()
çağrısının “Merhaba. Benim adım John Doe." Bunun yerine şunu alıyoruz: “Merhaba. Benim adım tanımsız." Bunun nedeni, ok işlevlerinin this
değerine sahip olmaması ve bu nedenle, this
bir ok işlevi içinde kullanmaya çalışmanın varsayılan olarak çevreleyen kapsamın this
olması ve Person
nesnesinin çevreleyen kapsamının tarayıcıda window
, veya module.exports
. Düğüm.
Bunu kanıtlamak için, aynı nesneyi tekrar kullanırsak, ancak global this'in name
özelliğini 'Jane Doe' gibi bir şeye ayarlarsak, ok işlevindeki this.name
'Jane Doe' döndürür, this
this
. kapsayan kapsam veya Person
nesnesinin ebeveynidir.
this.name = 'Jane Doe'; const Person = { name: 'John Doe', greeting: () => { console.log(`Hi. My name is ${this.name}.`); } } Person.greeting(); // Hi. My name is Jane Doe
Bu, 'Sözcük Kapsamı Belirleme' olarak bilinir ve nesnemizi şu şekilde yeniden düzenlemek için iki nokta üst üste ve oku kaybettiğimiz 'Kısa Sözdizimi' denilen şeyi kullanarak bu sorunu aşabiliriz:
const Person = { name: 'John Doe', greeting() { console.log(`Hi. My name is ${this.name}.`); } } Person.greeting() //Hi. My name is John Doe.
ES6 Sınıfları
JavaScript sınıfları hiçbir zaman desteklemese de, bunları her zaman yukarıdaki gibi nesnelerle taklit edebilirsiniz. EcmaScript 6, class
ve new
anahtar kelimeleri kullanan sınıflar için destek sağlar:
class Person { constructor(name) { this.name = name; } greeting() { console.log(`Hi. My name is ${this.name}.`); } } const person = new Person('John'); person.greeting(); // Hi. My name is John.
Yapıcı işlevi, nesneyi başlangıçta ayarlamak için içine argümanlar iletebileceğimiz new
anahtar sözcüğünü kullanırken otomatik olarak çağrılır. Bu, Java, C++ ve C# gibi daha statik olarak yazılan nesne yönelimli programlama dilleriyle deneyimi olan herhangi bir okuyucuya aşina olmalıdır.
OOP kavramları hakkında çok fazla ayrıntıya girmeden, bu tür bir başka paradigma, bir sınıfın diğerinden miras almasına izin veren “miras”tır. Örneğin, Car
adlı bir sınıf çok genel olacaktır - tüm arabaların ihtiyaç duyduğu "dur", "başlat" vb. gibi yöntemleri içerir. Bu durumda, sınıfın SportsCar
adlı bir alt kümesi, Car
temel işlemleri devralabilir ve özel olarak ihtiyaç duyduğu her şeyi geçersiz kılabilir. Böyle bir sınıfı aşağıdaki gibi gösterebiliriz:
class Car { constructor(licensePlateNumber) { this.licensePlateNumber = licensePlateNumber; } start() {} stop() {} getLicensePlate() { return this.licensePlateNumber; } // … } class SportsCar extends Car { constructor(engineRevCount, licensePlateNumber) { super(licensePlateNumber); // Pass licensePlateNumber up to the parent class. this.engineRevCount = engineRevCount; } start() { super.start(); } stop() { super.stop(); } getLicensePlate() { return super.getLicensePlate(); } getEngineRevCount() { return this.engineRevCount; } }
super
anahtar sözcüğünün, üst veya süper sınıftan özelliklere ve yöntemlere erişmemize izin verdiğini açıkça görebilirsiniz.
JavaScript Olayları
Olay, yanıt verme yeteneğine sahip olduğunuz gerçekleşen bir eylemdir. Diyelim ki uygulamanız için bir giriş formu oluşturuyorsunuz. Kullanıcı "gönder" düğmesine bastığında, bu olaya kodunuzdaki bir "olay işleyici" aracılığıyla tepki verebilirsiniz - tipik olarak bir işlev. Bu fonksiyon olay işleyicisi olarak tanımlandığında, “bir olay işleyicisi kaydettiriyoruz” deriz. Gönder düğmesi tıklaması için olay işleyici muhtemelen kullanıcı tarafından sağlanan girişin biçimlendirmesini kontrol edecek, SQL Enjeksiyonları veya Siteler Arası Komut Dosyası Çalıştırma gibi saldırıları önlemek için sterilize edecektir (lütfen istemci tarafında hiçbir kodun dikkate alınamayacağını unutmayın) Güvenli.Sunucudaki verileri her zaman sterilize edin - asla tarayıcıdan gelen hiçbir şeye güvenmeyin) ve ardından bir kullanıcının kimliğini doğrulamak ve onlara bir simge sunmak için bu kullanıcı adı ve şifre kombinasyonunun bir veritabanında çıkıp çıkmadığını kontrol edin.
Bu, Düğüm hakkında bir makale olduğundan, Düğüm Olay Modeline odaklanacağız.
Belirli olayları yaymak ve tepki vermek için Node'daki events
modülünü kullanabiliriz. Bir olay yayan herhangi bir nesne, EventEmitter
sınıfının bir örneğidir.
emit()
yöntemini çağırarak bir olay yayabilir ve her ikisi de EventEmitter
sınıfı aracılığıyla açığa çıkan on()
yöntemi aracılığıyla bu olayı dinleriz.
const EventEmitter = require('events'); const myEmitter = new EventEmitter();
myEmitter
artık EventEmitter
sınıfının bir örneği olduğundan, emit()
ve on()
öğelerine erişebiliriz:
const EventEmitter = require('events'); const myEmitter = new EventEmitter(); myEmitter.on('someEvent', () => { console.log('The "someEvent" event was fired (emitted)'); }); myEmitter.emit('someEvent'); // This will call the callback function above.
myEmitter.on()
ikinci parametresi, olay yayıldığında tetiklenecek olan geri çağırma işlevidir - bu olay işleyicisidir. CamelCase adlandırma kuralı önerilmesine rağmen, ilk parametre olayın adıdır ve istediğimiz herhangi bir şey olabilir.
Ek olarak, olay işleyici, olay yayıldığında aktarılan herhangi bir sayıda bağımsız değişkeni alabilir:
const EventEmitter = require('events'); const myEmitter = new EventEmitter(); myEmitter.on('someEvent', (data) => { console.log(`The "someEvent" event was fired (emitted) with data: ${data}`); }); myEmitter.emit('someEvent', 'This is the data payload');
Kalıtımı kullanarak, herhangi bir sınıfa 'EventEmitter'dan emit()
ve on()
yöntemlerini gösterebiliriz. Bu, bir Node.js sınıfı oluşturarak ve extends
üzerinde bulunan özellikleri devralmak için EventEmitter
ayrılmış anahtar sözcüğünü kullanarak yapılır:
const EventEmitter = require('events'); class MyEmitter extends EventEmitter { // This is my class. I can emit events from a MyEmitter object. }
Arabanın gövdesindeki jiroskoplardan, ivmeölçerlerden ve basınç göstergelerinden veri alan bir araç çarpışma bildirim programı oluşturduğumuzu varsayalım. Bir araç bir nesneyle çarpıştığında, bu harici sensörler çarpışmayı algılayacak, collide(...)
işlevini yürütecek ve toplanan sensör verilerini Nice JavaScript Nesnesi olarak ona iletecektir. Bu işlev, satıcıya çökmeyi bildiren bir collision
olayı yayar.
const EventEmitter = require('events'); class Vehicle extends EventEmitter { collide(collisionStatistics) { this.emit('collision', collisionStatistics) } } const myVehicle = new Vehicle(); myVehicle.on('collision', collisionStatistics => { console.log('WARNING! Vehicle Impact Detected: ', collisionStatistics); notifyVendor(collisionStatistics); }); myVehicle.collide({ ... });
Bu, kodu sınıfın çarpışma işlevinin içindeki olay işleyicisine koyabileceğimiz için karmaşık bir örnektir, ancak yine de Düğüm Olay Modelinin nasıl çalıştığını gösterir. Bazı öğreticilerin, bir nesnenin olay yaymasına izin util.inherits()
yöntemini göstereceğini unutmayın. Bu, extends
Sınıfları lehine kullanımdan kaldırılmıştır ve .
Düğüm Paket Yöneticisi
Node ve JavaScript ile programlama yaparken, npm
hakkında bir şeyler duymak oldukça yaygın olacaktır. Npm tam da bunu yapan bir paket yöneticisidir — JavaScript'teki yaygın sorunları çözen üçüncü taraf paketlerin indirilmesine izin verir. Yarn, Npx, Grunt ve Bower gibi başka çözümler de mevcuttur, ancak bu bölümde yalnızca npm
ve onu kullanarak basit bir Komut Satırı Arayüzü (CLI) aracılığıyla uygulamanız için bağımlılıkları nasıl kurabileceğinize odaklanacağız.
Sadece npm
ile basit başlayalım. NPM'de bulunan tüm paketleri görüntülemek için NpmJS ana sayfasını ziyaret edin. NPM Paketlerine bağlı olacak yeni bir projeye başladığınızda, projenizin kök dizinindeki terminal aracılığıyla npm init
çalıştırmanız gerekecek. Bir package.json
dosyası oluşturmak için kullanılacak bir dizi soru sorulacak. Bu dosya, tüm bağımlılıklarınızı depolar - uygulamanızın çalışmasına bağlı olduğu modüller, komut dosyaları - testleri çalıştırmak, projeyi oluşturmak, geliştirme sunucusunu başlatmak vb. için önceden tanımlanmış terminal komutları ve daha fazlası.
Bir paketi kurmak için npm install [package-name] --save
çalıştırmanız yeterlidir. save
bayrağı, paketin ve sürümünün package.json
dosyasına kaydedilmesini sağlayacaktır. npm
sürüm 5'ten beri, bağımlılıklar varsayılan olarak kaydedilir, bu nedenle --save
atlanabilir. Ayrıca, yeni yüklediğiniz paketin kodunu içeren yeni bir node_modules
klasörü göreceksiniz. Bu aynı zamanda sadece npm i [package-name]
olarak kısaltılabilir. Yararlı bir not olarak, node_modules
klasörü boyutu nedeniyle hiçbir zaman GitHub deposuna dahil edilmemelidir. GitHub'dan (veya başka bir sürüm yönetim sisteminden) bir repo klonladığınızda, dışarı çıkmak ve package.json
dosyasında tanımlanan tüm paketleri almak ve node_modules
dizinini otomatik olarak oluşturmak için npm install
komutunu çalıştırdığınızdan emin olun. Ayrıca belirli bir sürümde bir paket kurabilirsiniz: npm i [package-name]@1.10.1 --save
.
Bir paketi kaldırmak, bir paketi kurmaya benzer: npm remove [package-name]
.
Ayrıca global olarak bir paket de yükleyebilirsiniz. Bu paket, yalnızca üzerinde çalıştığınız projede değil, tüm projelerde kullanılabilecektir. Bunu npm i [package-name]
sonra -g
bayrağıyla yaparsınız. Bu, Google Firebase ve Heroku gibi CLI'ler için yaygın olarak kullanılır. Bu yöntemin sunduğu kolaylığa rağmen, paketleri global olarak kurmak genellikle kötü bir uygulama olarak kabul edilir, çünkü bunlar package.json
dosyasına kaydedilmezler ve başka bir geliştirici projenizi kullanmaya çalışırsa, gerekli tüm bağımlılıkları elde edemezler. npm install
.
API'ler ve JSON
API'ler programlamada çok yaygın bir paradigmadır ve bir geliştirici olarak kariyerinize yeni başlıyor olsanız bile, API'ler ve özellikle web ve mobil geliştirmede kullanımları muhtemelen daha sık ortaya çıkacaktır.
API, bir Uygulama Programlama Arayüzüdür ve temelde iki ayrılmış sistemin birbiriyle iletişim kurabileceği bir yöntemdir. Daha teknik terimlerle, bir API, bir sistem veya bilgisayar programının (genellikle bir sunucu) istekleri almasına ve uygun yanıtları (bir istemciye, ana bilgisayar olarak da bilinir) göndermesine izin verir.
Bir hava durumu uygulaması oluşturduğunuzu varsayalım. Bir kullanıcının adresini enlem ve boylam olarak coğrafi olarak kodlamanın bir yoluna ve ardından o belirli konumdaki mevcut veya tahmini hava durumunu elde etmenin bir yoluna ihtiyacınız var.
As a developer, you want to focus on building your app and monetizing it, not putting the infrastructure in place to geocode addresses or placing weather stations in every city.
Luckily for you, companies like Google and OpenWeatherMap have already put that infrastructure in place, you just need a way to talk to it — that is where the API comes in. While, as of now, we have developed a very abstract and ambiguous definition of the API, bear with me. We'll be getting to tangible examples soon.
Now, it costs money for companies to develop, maintain, and secure that aforementioned infrastructure, and so it is common for corporations to sell you access to their API. This is done with that is known as an API key, a unique alphanumeric identifier associating you, the developer, with the API. Every time you ask the API to send you data, you pass along your API key. The server can then authenticate you and keep track of how many API calls you are making, and you will be charged appropriately. The API key also permits Rate-Limiting or API Call Throttling (a method of throttling the number of API calls in a certain timeframe as to not overwhelm the server, preventing DOS attacks — Denial of Service). Most companies, however, will provide a free quota, giving you, as an example, 25,000 free API calls a day before charging you.
Up to this point, we have established that an API is a method by which two computer programs can communicate with each other. If a server is storing data, such as a website, and your browser makes a request to download the code for that site, that was the API in action.
Let us look at a more tangible example, and then we'll look at a more real-world, technical one. Suppose you are eating out at a restaurant for dinner. You are equivalent to the client, sitting at the table, and the chef in the back is equivalent to the server.
Since you will never directly talk to the chef, there is no way for him/her to receive your request (for what order you would like to make) or for him/her to provide you with your meal once you order it. We need someone in the middle. In this case, it's the waiter, analogous to the API. The API provides a medium with which you (the client) may talk to the server (the chef), as well as a set of rules for how that communication should be made (the menu — one meal is allowed two sides, etc.)
Now, how do you actually talk to the API (the waiter)? You might speak English, but the chef might speak Spanish. Is the waiter expected to know both languages to translate? What if a third person comes in who only speaks Mandarin? What then? Well, all clients and servers have to agree to speak a common language, and in computer programming, that language is JSON, pronounced JAY-sun, and it stands for JavaScript Object Notation.
At this point, we don't quite know what JSON looks like. It's not a computer programming language, it's just, well, a language, like English or Spanish, that everyone (everyone being computers) understands on a guaranteed basis. It's guaranteed because it's a standard, notably RFC 8259 , the JavaScript Object Notation (JSON) Data Interchange Format by the Internet Engineering Task Force (IETF).
Even without formal knowledge of what JSON actually is and what it looks like (we'll see in an upcoming article in this series), we can go ahead introduce a technical example operating on the Internet today that employs APIs and JSON. APIs and JSON are not just something you can choose to use, it's not equivalent to one out of a thousand JavaScript frameworks you can pick to do the same thing. It is THE standard for data exchange on the web.
Suppose you are building a travel website that compares prices for aircraft, rental car, and hotel ticket prices. Let us walk through, step-by-step, on a high level, how we would build such an application. Of course, we need our User Interface, the front-end, but that is out of scope for this article.
We want to provide our users with the lowest price booking method. Well, that means we need to somehow attain all possible booking prices, and then compare all of the elements in that set (perhaps we store them in an array) to find the smallest element (known as the infimum in mathematics.)
How will we get this data? Well, suppose all of the booking sites have a database full of prices. Those sites will provide an API, which exposes the data in those databases for use by you. You will call each API for each site to attain all possible booking prices, store them in your own array, find the lowest or minimum element of that array, and then provide the price and booking link to your user. We'll ask the API to query its database for the price in JSON, and it will respond with said price in JSON to us. We can then use, or parse, that accordingly. We have to parse it because APIs will return JSON as a string, not the actual JavaScript data type of JSON. This might not make sense now, and that's okay. We'll be covering it more in a future article.
Also, note that just because something is called an API does not necessarily mean it operates on the web and sends and receives JSON. The Java API, for example, is just the list of classes, packages, and interfaces that are part of the Java Development Kit (JDK), providing programming functionality to the programmer.
Peki. We know we can talk to a program running on a server by way of an Application Programming Interface, and we know that the common language with which we do this is known as JSON. But in the web development and networking world, everything has a protocol. What do we actually do to make an API call, and what does that look like code-wise? That's where HTTP Requests enter the picture, the HyperText Transfer Protocol, defining how messages are formatted and transmitted across the Internet. Once we have an understanding of HTTP (and HTTP verbs, you'll see that in the next section), we can look into actual JavaScript frameworks and methods (like fetch()
) offered by the JavaScript API (similar to the Java API), that actually allow us to make API calls.
HTTP And HTTP Requests
HTTP is the HyperText Transfer Protocol. It is the underlying protocol that determines how messages are formatted as they are transmitted and received across the web. Let's think about what happens when, for example, you attempt to load the home page of Smashing Magazine in your web browser.
You type the website URL (Uniform Resource Locator) in the URL bar, where the DNS server (Domain Name Server, out of scope for this article) resolves the URL into the appropriate IP Address. The browser makes a request, called a GET Request, to the Web Server to, well, GET the underlying HTML behind the site. The Web Server will respond with a message such as “OK”, and then will go ahead and send the HTML down to the browser where it will be parsed and rendered accordingly.
There are a few things to note here. First, the GET Request, and then the “OK” response. Suppose you have a specific database, and you want to write an API to expose that database to your users. Suppose the database contains books the user wants to read (as it will in a future article in this series). Then there are four fundamental operations your user may want to perform on this database, that is, Create a record, Read a record, Update a record, or Delete a record, known collectively as CRUD operations.
Let's look at the Read operation for a moment. Without incorrectly assimilating or conflating the notion of a web server and a database, that Read operation is very similar to your web browser attempting to get the site from the server, just as to read a record is to get the record from the database.
Bu, HTTP İsteği olarak bilinir. Bazı verileri almak için bir yerde bir sunucuya istekte bulunuyorsunuz ve bu nedenle, istek uygun şekilde "GET" olarak adlandırılıyor, büyük harf kullanımı bu tür istekleri belirtmenin standart bir yolu.
CRUD'nin Oluştur kısmı ne olacak? Peki, HTTP İstekleri hakkında konuşurken, bu bir POST isteği olarak bilinir. Tıpkı bir sosyal medya platformuna mesaj gönderebileceğiniz gibi, bir veritabanına yeni bir kayıt da gönderebilirsiniz .
CRUD Güncellemesi, bir kaynağı güncellemek için PUT veya PATCH Talebi kullanmamıza izin verir. HTTP'nin PUT'u ya yeni bir kayıt oluşturacak ya da eskisini güncelleyecek/değiştirecek.
Buna biraz daha ayrıntılı bakalım ve sonra PATCH'e geçeceğiz.
Bir API genellikle bir URL'deki belirli rotalara HTTP istekleri yaparak çalışır. Bir kullanıcının kitap listesini içeren bir DB ile konuşmak için bir API yaptığımızı varsayalım. O zaman bu kitapları URL .../books
adresinde görebiliriz. .../books
books'a yapılan bir POST isteği, .../books
yolunda tanımladığınız özelliklere (düşünme kimliği, başlık, ISBN, yazar, yayın verileri, vb.) sahip yeni bir kitap oluşturacaktır. Tüm kitapları şu anda .../books
konumunda depolayan temel veri yapısının ne olduğu önemli değil. Yalnızca API'nin verileri işlemek için bu uç noktayı (rota üzerinden erişilen) açığa çıkarmasını önemsiyoruz. Önceki cümle anahtardı: Bir POST isteği, ...books/
rotada yeni bir kitap oluşturur . O halde PUT ve POST arasındaki fark, PUT'un böyle bir kitap yoksa (POST'ta olduğu gibi) yeni bir kitap oluşturacağı veya kitap zaten söz konusu veri yapısında mevcutsa mevcut bir kitabın yerini alacağıdır.
Her kitabın şu özelliklere sahip olduğunu varsayalım: kimlik, başlık, ISBN, yazar, hasRead (boolean).
Ardından, daha önce görüldüğü gibi yeni bir kitap eklemek için .../books
books'a bir POST isteğinde bulunuruz. Bir kitabı tamamen güncellemek veya değiştirmek istersek, .../books/id
bir PUT isteğinde bulunuruz; burada id
, değiştirmek istediğimiz kitabın kimliğidir.
PUT, mevcut bir kitabın tamamen yerini alırken, PATCH, belirli bir kitapla ilgili bir şeyi günceller, belki de yukarıda tanımladığımız hasRead
boolean özelliğini değiştirir - bu nedenle, yeni verilerle birlikte …/books/id
göndererek bir PATCH isteğinde bulunuruz.
Bunun anlamını şu anda görmek zor olabilir, çünkü şimdiye kadar her şeyi teoride kurduk, ancak gerçekte HTTP isteği yapan herhangi bir somut kod görmedik. Bununla birlikte, GET'i bu makalede ele alarak buna yakında, geri kalanını da gelecek bir makalede anlatacağız.
Son bir temel CRUD işlemi vardır ve buna Sil denir. Tahmin edebileceğiniz gibi, böyle bir HTTP İsteğinin adı “DELETE”dir ve PATCH ile hemen hemen aynı şekilde çalışır ve kitabın kimliğinin bir rotada sağlanmasını gerektirir.
Şimdiye kadar, rotaların bir HTTP İsteği yaptığınız belirli URL'ler olduğunu ve bu uç noktaların API'nin sağladığı işlevler olduğunu ve ortaya çıkardığı verilere bir şeyler yaptığını öğrendik. Yani uç nokta, yolun diğer ucunda bulunan bir programlama dili işlevidir ve belirttiğiniz HTTP İsteğini gerçekleştirir. Ayrıca, API'ye gerçekte hangi istekleri yaptığınızı belirten POST, GET, PUT, PATCH, DELETE ve daha fazlası (HTTP fiilleri olarak bilinir) gibi terimler olduğunu öğrendik. JSON gibi, bu HTTP İstek Yöntemleri de İnternet Mühendisliği Görev Gücü (IETF) tarafından tanımlanan İnternet standartlarıdır, özellikle de RFC 7231, Bölüm Dört: İstek Yöntemleri ve RFC 5789, Bölüm İki: Yama Yöntemi, burada RFC, RFC'nin kısaltmasıdır. Yorum isteği.
Bu nedenle, geçirilen kimliğin parametre olarak bilindiği .../books/id
URL'sine bir GET isteğinde bulunabiliriz. Bir kaynak oluşturmak için .../books
books'a veya bir kaynağı değiştirmek/değiştirmek/güncellemek için .../books/id
POST, PUT veya PATCH isteğinde bulunabiliriz. Ayrıca belirli bir kitabı silmek için .../books/id
için SİLME isteğinde bulunabiliriz.
HTTP İstek Yöntemlerinin tam listesi burada bulunabilir.
Bir HTTP İsteği yaptıktan sonra bir yanıt alacağımızı da unutmamak gerekir. Özel yanıt, API'yi nasıl oluşturduğumuza göre belirlenir, ancak her zaman bir durum kodu almanız gerekir. Daha önce, web tarayıcınız web sunucusundan HTML istediğinde “Tamam” ile yanıt vereceğini söylemiştik. Bu, HTTP Durum Kodu, daha spesifik olarak HTTP 200 OK olarak bilinir. Durum kodu sadece bitiş noktasında belirtilen işlemin veya eylemin nasıl tamamlandığını belirtir (unutmayın, tüm işi yapan bizim fonksiyonumuzdur). HTTP Durum Kodları sunucu tarafından geri gönderilir ve muhtemelen aşina olduğunuz birçok kod vardır, örneğin 404 Bulunamadı (kaynak veya dosya bulunamadı, bu .../books/id
adresine GET isteğinde bulunmak gibi olacaktır. .../books/id
, böyle bir kimliğin bulunmadığı durumlarda.)
HTTP Durum Kodlarının tam listesi burada bulunabilir.
MongoDB
MongoDB, Firebase Gerçek Zamanlı Veritabanına benzer, ilişkisel olmayan, NoSQL bir veritabanıdır. Veritabanıyla MongoDB Native Driver veya Mongoose gibi bir Düğüm paketi aracılığıyla konuşacaksınız.
MongoDB'de veriler, MySQL, PostgreSQL veya SQLite gibi ilişkisel veritabanlarından oldukça farklı olan JSON'da depolanır. Her ikisine de veritabanları denir; SQL Tabloları Koleksiyonlar, SQL Tablo Satırları Belgeler ve SQL Tablo Sütunları Alanlar olarak adlandırılır.
MongoDB Veritabanını, ilk Bookshelf API'mizi oluşturduğumuzda, bu seride gelecek bir makalede kullanacağız. Yukarıda listelenen temel CRUD İşlemleri bir MongoDB Veritabanında gerçekleştirilebilir.
Atlas Cluster'da canlı bir veritabanı oluşturmayı ve MongoDB Native Driver ile buna CRUD İşlemleri yapmayı öğrenmek için MongoDB Dokümanlarını baştan sona okumanız önerilir. Bu serinin bir sonraki makalesinde, yerel bir veritabanı ve bir bulut üretim veritabanının nasıl kurulacağını öğreneceğiz.
Komut Satırı Düğümü Uygulaması Oluşturma
Bir uygulama oluştururken, birçok yazarın tüm kod tabanını makalenin başına döktüğünü ve ardından her satırı açıklamaya çalıştığını göreceksiniz. Bu metinde, farklı bir yaklaşım izleyeceğim. Gittikçe uygulamayı oluşturarak kodumu satır satır açıklayacağım. Modülerlik veya performans konusunda endişelenmeyeceğim, kod tabanını ayrı dosyalara bölmeyeceğim ve DRY İlkesini izlemeyeceğim veya kodu yeniden kullanılabilir hale getirmeye çalışmayacağım. Sadece öğrenirken, işleri olabildiğince basit hale getirmek yararlıdır ve bu yüzden burada benim de yaklaşımım bu olacaktır.
Ne inşa ettiğimiz konusunda net olalım. Kullanıcı girişi ile ilgilenmeyeceğiz ve bu nedenle Yargs gibi paketleri kullanmayacağız. Ayrıca kendi API'mizi de oluşturmayacağız. Bu, Express Web Application Framework'ü kullandığımızda, bu dizinin sonraki bir makalesinde gelecek. Bu yaklaşımı, çoğu öğreticinin yaptığı gibi, Node.js'yi Express ve API'lerin gücüyle birleştirmemek için alıyorum. Bunun yerine, üçüncü taraf bir JavaScript kitaplığı kullanan harici bir API'den veri çağırmak ve ondan veri almak için (pek çok yöntemden) birini sağlayacağım. Arayacağımız API, Node'dan erişeceğimiz ve çıktısını terminale, belki de “güzel yazdırma” olarak bilinen bazı biçimlendirmelerle dökeceğimiz bir Hava Durumu API'sidir. Adımları Ocak 2019 itibariyle doğru sonuçları sağlayan API'nin nasıl kurulacağı ve API Anahtarının nasıl elde edileceği dahil olmak üzere tüm süreci ele alacağım.
Bu proje için OpenWeatherMap API'sini kullanacağız, bu nedenle başlamak için OpenWeatherMap kayıt sayfasına gidin ve formla bir hesap oluşturun. Giriş yaptıktan sonra, gösterge tablosu sayfasında (burada bulunur) API Anahtarları menü öğesini bulun. Yeni bir hesap oluşturduysanız, API Anahtarınız için bir ad seçmeniz ve "Oluştur" düğmesine basmanız gerekir. Yeni API Anahtarınızın işlevsel olması ve hesabınızla ilişkilendirilmesi en az 2 saat sürebilir.
Uygulamayı oluşturmaya başlamadan önce, API Anahtarımızı nasıl biçimlendireceğimizi öğrenmek için API Belgelerini ziyaret edeceğiz. Bu projede, o konumdaki hava durumu bilgisini elde etmek için bir posta kodu ve bir ülke kodu belirleyeceğiz.
Dokümanlardan, bunu yaptığımız yöntemin aşağıdaki URL'yi sağlamak olduğunu görebiliriz:
api.openweathermap.org/data/2.5/weather?zip={zip code},{country code}
İçine veri girebileceğimiz:
api.openweathermap.org/data/2.5/weather?zip=94040,us
Şimdi, bu API'den ilgili verileri gerçekten elde etmeden önce, yeni API Anahtarımızı bir sorgu parametresi olarak sağlamamız gerekecek:
api.openweathermap.org/data/2.5/weather?zip=94040,us&appid={YOUR_API_KEY}
Şimdilik, {YOUR_API_KEY}
yer tutucusunu bir hesaba kaydolduğunuzda daha önce edindiğiniz API Anahtarı ile değiştirerek bu URL'yi web tarayıcınızda yeni bir sekmeye kopyalayın.
Gördüğünüz metin aslında JSON'dur - daha önce tartışıldığı gibi web'in üzerinde anlaşmaya varılan dili.
Bunu daha fazla incelemek için Google Chrome'da Ctrl + Shift + I tuşlarına basarak Chrome Geliştirici araçlarını açın ve ardından Ağ sekmesine gidin. Şu anda, burada veri olmamalıdır.
Ağ verilerini gerçekten izlemek için sayfayı yeniden yükleyin ve sekmenin yararlı bilgilerle doldurulmasını izleyin. Aşağıdaki resimde gösterildiği gibi ilk bağlantıya tıklayın.
Bu bağlantıya tıkladığınızda, başlıklar gibi HTTP'ye özgü bilgileri görebiliriz. Üstbilgiler API'den yanıt olarak gönderilir (bazı durumlarda API'ye kendi üstbilgilerinizi de gönderebilirsiniz veya hatta kendi API'nizi oluştururken geri göndermek için kendi özel üstbilgilerinizi (genellikle x-
ön ekli) oluşturabilirsiniz. ) ve yalnızca istemcinin veya sunucunun ihtiyaç duyabileceği ek bilgileri içerir.
Bu durumda API'ye bir HTTP GET İsteği yaptığımızı ve HTTP Status 200 OK ile yanıt verdiğini görebilirsiniz. Ayrıca, “Yanıt Başlıkları” bölümünde listelendiği gibi, geri gönderilen verilerin JSON'da olduğunu da görebilirsiniz.
Önizleme sekmesine basarsanız, JSON'u gerçekten bir JavaScript Nesnesi olarak görüntüleyebilirsiniz. Tarayıcınızda görebileceğiniz metin sürümü bir dizedir, çünkü JSON her zaman web üzerinden bir dize olarak iletilir ve alınır. Bu nedenle, kodumuzdaki JSON'u daha okunabilir bir biçime getirmek için ayrıştırmamız gerekiyor - bu durumda (ve hemen hemen her durumda) - bir JavaScript Nesnesi.
Bunu otomatik olarak yapmak için Google Chrome Uzantısı “JSON Görünümü”nü de kullanabilirsiniz.
Uygulamamızı oluşturmaya başlamak için bir terminal açıp yeni bir kök dizin oluşturacağım ve ardından içine cd
. İçeri girdikten sonra, yeni bir app.js
dosyası oluşturacağım, varsayılan ayarlarla bir package.json
dosyası oluşturmak için npm init
çalıştıracağım ve ardından Visual Studio Code'u açacağım.
mkdir command-line-weather-app && cd command-line-weather-app touch app.js npm init code .
Daha sonra Axios'u indireceğim, bunun package.json
dosyama eklendiğini doğrulayacağım ve node_modules
klasörünün başarıyla oluşturulduğunu not edeceğim.
Tarayıcıda, URL Çubuğuna uygun URL'yi manuel olarak yazarak elle bir GET İsteği yaptığımızı görebilirsiniz. Axios, bunu Node.js içinde yapmama izin verecek.
Şu andan itibaren, aşağıdaki kodların tümü app.js
dosyasının içine yerleştirilecek ve her bir snippet birbiri ardına yerleştirilecektir.
Yapacağım ilk şey, daha önce kurduğumuz Axios paketini gerektirmek.
const axios = require('axios');
Artık Axios'a erişimimiz var ve axios
sabiti aracılığıyla ilgili HTTP İsteklerini yapabiliriz.
Genel olarak, API çağrılarımız dinamik olacaktır - bu durumda URL'mize farklı posta kodları ve ülke kodları eklemek isteyebiliriz. Bu nedenle, URL'nin her bölümü için sabit değişkenler oluşturacağım ve ardından bunları ES6 Şablon Dizeleri ile bir araya getireceğim. İlk olarak, API Anahtarımızın yanı sıra URL'mizin asla değişmeyecek kısmına sahibiz:
const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here';
Posta kodumuzu ve ülke kodumuzu da atayacağım. Kullanıcı girdisi beklemiyoruz ve verileri kodlamak oldukça zor olduğundan, çoğu durumda let
kullanmak daha yararlı olsa da, bunları da sabit yapacağım.
const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us';
Şimdi bu değişkenleri, Axios'u kullanarak GET İstekleri yapmak için kullanabileceğimiz tek bir URL'de bir araya getirmemiz gerekiyor:
const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`;
Bu noktaya kadar app.js
dosyamızın içeriği:
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`;
Yapılması gereken tek şey, o URL'ye bir GET İsteği yapmak için axios
kullanmaktır. Bunun için axios
tarafından sağlanan get(url)
yöntemini kullanacağız.
axios.get(ENTIRE_API_URL)
axios.get(...)
aslında bir Söz döndürür ve başarı geri çağırma işlevi, tarayıcıda gördüğünüzün aynısı olan API'den gelen yanıta erişmemizi sağlayacak bir yanıt argümanını alır. Ayrıca hataları yakalamak için bir .catch()
yan tümcesi ekleyeceğim.
axios.get(ENTIRE_API_URL) .then(response => console.log(response)) .catch(error => console.log('Error', error));
Şimdi bu kodu terminalde node app.js
ile çalıştırırsak, geri aldığımız yanıtın tamamını görebileceksiniz. Ancak, yalnızca posta kodunun sıcaklığını görmek istediğinizi varsayalım - o zaman yanıttaki bu verilerin çoğu sizin için yararlı değildir. Axios aslında, yanıtın bir özelliği olan veri nesnesindeki API'den gelen yanıtı döndürür. Bu, sunucudan gelen response.data
aslında answer.data konumunda bulunduğu anlamına gelir, bu nedenle bunu geri çağırma işlevinde yazdıralım: console.log(response.data)
.
Şimdi, web sunucularının her zaman bir dize olarak JSON ile ilgilendiğini söyledik ve bu doğru. Bununla birlikte, response.data
zaten bir nesne olduğunu fark edebilirsiniz ( console.log(typeof response.data)
çalıştırıldığında belirgindir) - onu JSON.parse()
ile ayrıştırmak zorunda değildik. Bunun nedeni, Axios'un perde arkasında bunu bizim için halletmesidir.
Console.log console.log(response.data)
çalıştırıldığında terminaldeki çıktı, console.log(JSON.stringify(response.data, undefined, 2))
çalıştırılarak biçimlendirilebilir — "oldukça basılmış". JSON.stringify()
, bir JSON nesnesini bir dizgeye dönüştürür ve nesneyi, bir filtreyi ve yazdırırken girintilenecek karakter sayısını alır. Bunun sağladığı yanıtı görebilirsiniz:
{ "coord": { "lon": -118.24, "lat": 33.97 }, "weather": [ { "id": 800, "main": "Clear", "description": "clear sky", "icon": "01d" } ], "base": "stations", "main": { "temp": 288.21, "pressure": 1022, "humidity": 15, "temp_min": 286.15, "temp_max": 289.75 }, "visibility": 16093, "wind": { "speed": 2.1, "deg": 110 }, "clouds": { "all": 1 }, "dt": 1546459080, "sys": { "type": 1, "id": 4361, "message": 0.0072, "country": "US", "sunrise": 1546441120, "sunset": 1546476978 }, "id": 420003677, "name": "Lynwood", "cod": 200 }
Şimdi, aradığımız sıcaklığın response.data
nesnesinin main
özelliğinde yer aldığı açıktır, bu nedenle buna response.data.main.temp
çağırarak erişebiliriz. Şimdiye kadar uygulamanın koduna bakalım:
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`; axios.get(ENTIRE_API_URL) .then(response => console.log(response.data.main.temp)) .catch(error => console.log('Error', error));
Geri aldığımız sıcaklık aslında Kelvin'dedir. Bu, tüm iç mekanların tüm termal hareketlerinin gerçekleştiği sıcaklık olan bir "mutlak sıfır" noktası sağlaması nedeniyle genellikle Fizik, Kimya ve Termodinamikte kullanılan bir sıcaklık ölçeğidir. parçacıklar durur. Bunu aşağıdaki formüllerle Fahrenheit veya Celcius'a çevirmemiz yeterli:
F = K * 9/5 - 459.67
C = K - 273.15
Bu dönüşümle yeni verileri yazdırmak için başarı geri aramamızı güncelleyelim. Ayrıca Kullanıcı Deneyimi amaçları için uygun bir cümle ekleyeceğiz:
axios.get(ENTIRE_API_URL) .then(response => { // Getting the current temperature and the city from the response object. const kelvinTemperature = response.data.main.temp; const cityName = response.data.name; const countryName = response.data.sys.country; // Making K to F and K to C conversions. const fahrenheitTemperature = (kelvinTemperature * 9/5) — 459.67; const celciusTemperature = kelvinTemperature — 273.15; // Building the final message. const message = ( `Right now, in \ ${cityName}, ${countryName} the current temperature is \ ${fahrenheitTemperature.toFixed(2)} deg F or \ ${celciusTemperature.toFixed(2)} deg C.`.replace(/\s+/g, ' ') ); console.log(message); }) .catch(error => console.log('Error', error));
message
değişkeninin etrafındaki parantezler gerekli değildir, sadece güzel görünürler - React'te JSX ile çalışırken olduğu gibi. Ters eğik çizgiler, şablon dizesinin yeni bir satır biçimlendirmesini durdurur ve replace()
String prototip yöntemi, Normal İfadeler (RegEx) kullanarak boşluktan kurtulur. toFixed()
Number prototip yöntemleri, bir kayan noktayı belirli sayıda ondalık basamağa yuvarlar - bu durumda iki.
Bununla, son app.js
aşağıdaki gibi görünür:
const axios = require('axios'); // API specific settings. const API_URL = 'https://api.openweathermap.org/data/2.5/weather?zip='; const API_KEY = 'Your API Key Here'; const LOCATION_ZIP_CODE = '90001'; const COUNTRY_CODE = 'us'; const ENTIRE_API_URL = `${API_URL}${LOCATION_ZIP_CODE},${COUNTRY_CODE}&appid=${API_KEY}`; axios.get(ENTIRE_API_URL) .then(response => { // Getting the current temperature and the city from the response object. const kelvinTemperature = response.data.main.temp; const cityName = response.data.name; const countryName = response.data.sys.country; // Making K to F and K to C conversions. const fahrenheitTemperature = (kelvinTemperature * 9/5) — 459.67; const celciusTemperature = kelvinTemperature — 273.15; // Building the final message. const message = ( `Right now, in \ ${cityName}, ${countryName} the current temperature is \ ${fahrenheitTemperature.toFixed(2)} deg F or \ ${celciusTemperature.toFixed(2)} deg C.`.replace(/\s+/g, ' ') ); console.log(message); }) .catch(error => console.log('Error', error));
Çözüm
Bu makalede, eşzamanlı ve eşzamansız istekler arasındaki farklardan geri arama işlevlerine, yeni ES6 özelliklerine, olaylara, paket yöneticilerine, API'lere, JSON ve Köprü Metni Aktarım Protokolü, İlişkisel Olmayan Veritabanlarına kadar Düğümün nasıl çalıştığı hakkında çok şey öğrendik. ve hatta bu yeni bulunan bilgilerin çoğunu kullanarak kendi komut satırı uygulamamızı oluşturduk.
Bu dizinin gelecekteki makalelerinde, Çağrı Yığını, Olay Döngüsü ve Düğüm API'lerine derinlemesine bakacağız, Kökenler Arası Kaynak Paylaşımı (CORS) hakkında konuşacağız ve bir Tam Veritabanları, uç noktalar, kullanıcı kimlik doğrulaması, belirteçler, sunucu tarafı şablon oluşturma ve daha fazlasını kullanan Yığın Kitaplık API'sı.
Buradan kendi Düğüm uygulamalarınızı oluşturmaya başlayın, Düğüm belgelerini okuyun, dışarı çıkın ve ilginç API'ler veya Düğüm Modülleri bulun ve bunları kendiniz uygulayın. Dünya sizin istiridyenizdir ve gezegendeki en büyük bilgi ağına, yani İnternet'e erişim parmaklarınızın ucundadır. Avantajınız için kullanın.
SmashingMag'de Daha Fazla Okuma :
- REST API'lerini Anlama ve Kullanma
- Regex Yazma Şeklinizi Değiştirecek Yeni JavaScript Özellikleri
- Node.js'yi Hızlı Tutmak: Yüksek Performanslı Node.js Sunucuları Yapmak İçin Araçlar, Teknikler ve İpuçları
- Web Speech API ve Node.js ile Basit Bir AI Chatbot Oluşturma