table of contents - alumnitutorial.com · most of node.js beginners in my country indonesia is...
Post on 18-Mar-2019
217 Views
Preview:
TRANSCRIPT
1.1
1.2
1.2.1
1.2.2
1.3
1.3.1
1.3.2
1.4
1.4.1
1.5
1.6
1.6.1
1.6.2
1.7
1.7.1
1.7.2
1.8
1.8.1
1.8.1.1
1.8.1.2
1.8.2
1.9
1.9.1
1.9.1.1
1.9.1.2
1.9.1.2.1
1.9.2
1.9.2.1
1.9.3
1.9.3.1
TableofContentsIntroduction
Node.js
JavaScriptDiServer
Node.jsInAction
AsinkronI/O&Event
PHP&ServerHTTPApache
Javascript&Node.js
ServerHTTPDasar
MenjalankanServer
ServerFileStatis
PemrosesanDataFormHTML
URLEncode
MultipartData
Modulenpm
Konsep
Paketnpm
ExpressJS
ServerFile
Middleware
AksesServer
ServerREST
Database
SQLite
NodeSqlite3
Enkripsi
sqlcipher
MySQL
NodeMySQL
MongoDB
NodeMongoDB
2
1.9.3.2
1.10
1.10.1
1.10.2
1.11
1.11.1
1.11.2
1.11.3
1.12
1.12.1
1.12.2
1.12.3
1.13
1.14
1.15
Mongoose
Testing
REST
Automasi
ToDataURI
Penggunaan
todatauri.js
KoneksiMySQL
PersonRESTAPI
CaraKerja
Server
Pengetesan
ImageUploader
MemakaiES6
TentangPengarang
3
AplikasiWebNode.jsNote:ThisbookiswritteninBahasaIndonesiaandthemainreasonforthatisbecausemostofNode.jsbeginnersinmycountryIndonesiaishavingdifficultiestofindNode.jsresourceswritteninmynativelanguage.
BukuinicocokbagisiapasajayanginginmulaibelajarpemrogramandiplatformNode.jskhususnyauntukmembangunaplikasiweb.SyaratyangdibutuhkanadalahpembacasetidaknyapernahatausudahbisamemakaibahasapemrogramanJavaScript.
Ebookinibisaandaaksesdiduatempatyaitu:
GithubIDJS(versionline).Gitbook(versionline,PDF,Epub&Mobi).
FeedbackUntukpertanyaan,kesalahanketikataupermintaansilahkanmengisiGithubissue.
LisensiAplikasiWebNode.jsolehEquanPr.dikerjakandibawahlisensiCreativeCommonsAttribution-NonCommercial4.0InternationalLicense.
Introduction
4
Node.jsJavascriptmerupakanbahasapemrogramanyanglengkaphanyasajaselamainidipakaisebagaibahasauntukpengembanganaplikasiwebyangberjalanpadasisiclientataubrowsersaja.TetapisejakditemukannyaNode.jsolehRyanDhalpadatahun2009,JavascriptbisadigunakansebagaibahasapemrogramandisisiserversekelasdenganPHP,ASP,C#,RubydlldengankatalainNode.jsmenyediakanplatformuntukmembuataplikasiJavascriptdapatdijalankandisisiserver.
UntukmengeksekusiJavascriptsebagaibahasaserverdiperlukanengineyangcepatdanmempunyaiperformansiyangbagus.EngineJavascriptdariGooglebernamaV8yangdipakaiolehNode.jsyangmerupakanengineyangsamayangdipakaidibrowserGoogleChrome.
Node.js
5
JavaScriptDiServerTakterelakkanbahwaJavascriptmerupakanbahasapemrogramanyangpalingpopuler.JikaandasebagaideveloperpernahmengembangkanaplikasiwebmakapenggunaanJavascriptpastitidakterhindarkan.
SekarangdenganberjalannyaJavascriptdiserverlaluapakeuntunganyangandaperolehdenganmempelajariNode.js,kuranglebihsepertiini:
Pengembanghanyamemakaisatubahasauntukmengembangkanaplikasilengkapclient&serversehinggamengurangiLearningCurveuntukmempelajaribahasaserveryanglain.
Sharingkodeantaraclientdanserveratauistilahnyacodereuse.
JavascriptsecaranativemendukungJSONyangmerupakanstandartransferdatayangbanyakdipakaisaatinisehinggauntukmengkonsumsidata-datadaripihakketigapemrosesandiNode.jsakansangatmudahsekali.
DatabaseNoSQLsepertiMongoDBdanCouchDBmendukunglangsungJavascriptsehinggainterfacingdengandatabaseiniakanjauhlebihmudah.
Node.jsmemakaiV8yangselalumengikutiperkembanganstandarECMAScript,jaditidakperluadakekhawatiranbahwabrowsertidakakanmendukungfitur-fiturdiNode.js.
JavaScriptDiServer
6
Node.jsInActionSupayaandalebihtertarikdalambelajarNode.jsberikutbeberapawebsiteterkenalyangsudahmemakaiNode.js
www.myspace.com
www.yummly.com
www.shutterstock.com
Node.jsInAction
7
www.learnboost.com
ApakahmasihraguuntukmemakaiNode.js?...KalaumasihpenasaranapayangmembuatNode.jsberbedadaribackendpadaumumnya,silahkandilanjutkanmembaca:smile:
Node.jsInAction
9
AsinkronI/O&EventTidaksepertikebanyakanbahasabackendlainnyaoperasifungsidijavascriptlebihbersifatasinkrondanbanyakmenggunakaneventdemikianjugadenganNode.js.SebelumpenjelasanlebihlanjutmarikitalihatterlebihdahulutentangmetodesinkronsepertiyangdipakaipadaPHPdenganwebserverApache.
AsinkronI/O&Event
10
PHP&ServerHTTPApacheMarikitalihatcontohberikutyaituoperasifungsiakseskedatabaseMySQLolehPHPyangdilakukansecarasinkron
$hasil=mysql_query("SELECT*FROMTabelAnggota");
print_r($hasil);
pengambilandataolehmysql_query()diatasakandijalankandanoperasiberikutnyaprint_r()akandiblokatautidakakanberjalansebelumakseskedatabaseselesai.YangperlumenjadiperhatiandisiniyaituprosesInputOutputatauI/Oakseskedatabaseolehmysql_query()dapatmemakanwaktuyangrelatifmungkinbeberapadetikataumenittergantungdariwaktulatensidariI/O.Waktulatensiinitergantungdaribanyakhalseperti
QuerydatabaselambatakibatbanyakpenggunayangmengaksesKualitasjaringanuntukakseskedatabasejelekProsesbacatuliskediskkomputerdatabaseyangmembutuhkanwaktu...
SebelumprosesI/Oselesaimakaselamabeberapadetikataumenittersebutstatedariprosesmysql_query()bisadibilangidleatautidakmelakukanapa-apa.
LalujikaprosesI/Odiblokbagaimanajikaadarequestlagidariuser?apayangakandilakukanolehserveruntukmenanganirequestini?..penyelesaiannyayaitudenganmemakaipendekatanprosesmultithread.Melaluipendekataninitiapkoneksiyangterjadiakanditanganiolehthread.Threaddisinibisadikatakansebagaitaskyangdijalankanolehprosesorkomputer.
SepertinyapermasalahanI/Oyangterblokterselesaikandenganpendekatanmetodeinitetapidenganbertambahnyakoneksiyangterjadimakathreadakansemakinbanyaksehinggaprosesorakansemakinterbebani,belumlagiuntukswitchingantarthreadmenyebabkankonsumsimemory(RAM)komputeryangcukupbesar.
BerikutcontohbenchmarkantarawebserverApachedanNginx(serverHTTPsepertihalnyaApachehanyasajaNginxmemakaisistemasinkronI/OdaneventyangmiripNode.js).Gambarinidiambildarigoo.gl/pvLL4
PHP&ServerHTTPApache
11
BisadilihatbahwaNginxbisamenanganirequestyangjauhlebihbanyakdaripadawebserverApachepadajumlahkoneksibersamayangsemakinnaik.
PHP&ServerHTTPApache
12
Javascript&Node.jsKembalikeJavascript!.Untukmengetahuiapayangdimaksuddenganpemrogramanasinkronbisalebihmudahdenganmemakaipendekatancontohkode.PerhatikankodeJavascriptpadaNode.jsberikut
varfs=require('fs');
fs.readFile('./resource.json',function(err,data){
if(err)throwerr;
console.log(JSON.parse(data));
});
console.log('Selanjutnya...');
fungsireadFile()akanmembacamembacaisidarifileresource.jsonsecaraasinkronyangartinyaproseseksekusiprogramtidakakanmenunggupembacaanfileresource.jsonsampaiselesaitetapiprogramakantetapmenjalankankodeJavascriptselanjutnyayaituconsole.log('Selanjutnya...').Sekarnglihatapayangterjadijikakodejavascriptdiatasdijalankan
Jikaprosespembacaanfileresource.jsonselesaimakafungsicallbackpadareadFile()akandijalankandanhasilnyaakanditampilkanpadaconsole.Yah,fungsicallbackmerupakankonsepyangpentingdalamprosesI/OyangasinkronkarenamelaluifungsicallbackinidatadatayangdikembalikanolehprosesI/Oakandiproses.
LalubagaimanaplatformNode.jsmengetahuikalausuatuprosesitutelahselesaiatautidak?...jawabannyaadalahEventLoop.Event-eventyangterjadikarenaprosesasinkronsepertipadafungsifs.readFile()akanditanganiolehyangnamanyaEventLoopini.
Campuranteknologiantaraeventdrivendanprosesasinkroninimemungkinkanpembuatanaplikasidenganpenggunaandatasecaramasifdanreal-time.SifatkomunikasiNode.jsI/Oyangringandanbisamenanganiusersecarabersamaandalamjumlahrelatifbesartetapitetapmenjagastatedarikoneksisupayatetapterbukadandenganpenggunaanmemoriyangcukupkecilmemungkinkanpengembanganaplikasidenganpenggunaandatayangbesardankolaboratif...Yeah,Node.jsFTW!:metal:
Javascript&Node.js
13
ServerHTTPDasarPenggunaanNode.jsyangrevolusioneryaitusebagaiserver.Yup...mungkinkitaterbiasamemakaiserversepertiApache-PHP,Nginx-PHP,Java-Tomcat-ApacheatauIIS-ASP.NETsebagaipemrosesdatadisisiserver,tetapisekarangsemuaitubisatergantikandenganmemakaiJavaScript-Node.js!.LihatcontohdasardariserverNode.jsberikut(kodesumberpadadirektoricodepadarepositoriini)
server-http.js
varhttp=require('http'),
PORT=3400;
varserver=http.createServer(function(req,res){
varbody="<pre>HaruskahbelajarNode.js?</pre><p><h3>...YoMesto!</h3></p>"
res.writeHead(200,{
'Content-Length':body.length,
'Content-Type':'text/html',
'Pesan-Header':'PengenalanNode.js'
});
res.write(body);
res.end();
});
server.listen(PORT);
console.log("Port"+PORT+":Node.jsServer...");
PakethttpmerupakanpaketbawaandariplatformNode.jsyangmendukungpenggunaanfitur-fiturprotokolHTTP.ObjectservermerupakanobjectyangdikembalikandarifungsicreateServer().
varserver=http.createServer([requestListener])
TiaprequestyangterjadiakanditanganiolehfungsicallbackrequestListener.Carakerjacallbackinihampirsamadenganketikakitamenekantombolbuttonhtmlyangmempunyaiatributeventonclick,jikaditekanmakafungsiyangteregistrasioleheventonclickyaituclickHandler(event)akandijalankan.
onclick-button.html
ServerHTTPDasar
15
<script>
functionclickHandler(event){
console.log(event.target.innerHTML+"Terus!");
}
</script>
<buttononclick="clickHandler(event)">TEKAN</button>
SamahalnyadengancallbackrequestListenerpadaobjectserverinijikaadarequestmakarequestListenerakandijalankan
function(req,res){
varbody="<pre>HaruskahbelajarNode.js?</pre><p><h3>...YoMesto!</h3></p>"
res.writeHead(200,{
'Content-Length':body.length,
'Content-Type':'text/html',
'Pesan-Header':'PengenalanNode.js'
});
res.write(body);
res.end();
}
PakethttpNode.jsmemberikankeleluasanbagideveloperuntukmembangunservertingkatrendah.Bahkanmudahsajakalauharusmen-settingnilaifieldheaderdariHTTP.
SepertipadacontohdiatasagarrespondarirequestdiperlakukansebagaiHTMLolehbrowsermakanilaifieldContent-Typeharusberupatext/html.SettinginibisadilakukanmelaluimetodewriteHead(),res.setHeader(field,value)danbeberapametodelainnya.
Untukmembacaheaderbisadipakaifungsisepertires.getHeader(field,value)danuntukmenghapusfieldheadertertentudenganmemakaifungsires.removeHeader(field).Perludiingatbahwasettingheaderdilakukansebelumfungsires.write()ataures.end()dijalankankarenajikares.write()dijalankantetapikemudianadaperubahanfieldheadermakaperubahaniniakandiabaikan.
SatuhallagiyaitutentangkodestatusdariresponHTTP.Kodestatusinibisadisettingselain200(requesthttpsukses),misalnyabiladiperlukanhalamanerrordengankodestatus404.
ServerHTTPDasar
16
MenjalankanServerUntukmenjalankanserverNode.jsketikperintahberikutditerminal
$nodeserver-http.js
Port3400:Node.jsServer...
Bukabrowser(chrome)danbukaurlhttp://localhost:3400kemudianketikCTRL+SHIFT+IuntukmembukaChromeDevTool,dengantoolinibisadilihatresponheaderdariHTTPdimanabeberapafieldnyatelahdisetsebelumnya(lingkaranmerahpadascreenshotdibawahini).
MenjalankanServer
17
ServerFileStatisAplikasiwebmemerlukanfile-filestatissepertiCSS,fontdangambarataufile-filelibraryJavaScriptagaraplikasiwebbekerjasebagaimanamestinya.File-fileinisengajadipisahkanagarterstrukturdansecarabestpracticesfile-fileinimemangharusdipisahkan.LalubagaimanacaranyaNode.jsbisamenyediakanfile-fileini?...okmarikitabuatserverNode.jsyangfungsinyauntukmenyediakanfilestatis.
AgarserverNode.jsbisamengirimkanfilestatiskeklienmakaserverperlumengetahuipathatautempatdimanafiletersebutberada.
Node.jsbisamengirimkanfiletersebutsecarastreamingmelaluifungsifs.createReadStream().SebelumdijelaskanlebihlanjutmungkinbisadilihatataudicobasajaserverfileNode.jsdibawahini
server-file.js
ServerFileStatis
18
varhttp=require('http'),
parse=require('url').parse,
join=require('path').join,
fs=require('fs'),
root=join(__dirname,'www'),
PORT=3300,
server=http.createServer(function(req,res){
varurl=parse(req.url),
path=join(root,url.pathname),
stream=fs.createReadStream(path);
stream.on('data',function(bagian){
res.write(bagian);
});
stream.on('end',function(){
res.end();
});
stream.on('error',function(){
res.setHeader('Content-Type','text/html');
varurl_demo="http://localhost:"+PORT+"/index.html";
res.write("cobabuka<ahref="+url_demo+">"+url_demo+"</a>");
res.end();
})
});
server.listen(PORT);
console.log('Port'+PORT+':ServerFile');
Berikutsedikitpenjelasandarikodediatas
__dirnamemerupakanvariabelglobalyangdisediakanolehNode.jsyangberisipathdirektoridarifileyangsedangaktifmengeksekusi__dirname.rootmerupakandirektorirootataureferensitempatdimanafile-fileyangakandikirimkanolehserverNode.js.Padakodeserverdiatasdirektorirootdisettingpadadirektoriwww.pathadalahpathfileyangbisadidapatkandenganmenggabungkanpathdirektorirootdanpathname.pathnameyangdimaksuddisinimisalnyajikaURLyangdimintayaituhttp://localhost:3300/index.htmlmakapathnameadalah/index.html.Nilaivariabelpathdihasilkandenganmemakaifungsijoin().
varpath=join(root,url.pathname)
ServerFileStatis
19
streamyangdikembalikanolehfungsifs.createReadStream()merupakanclassstream.Readable.Objekstreaminimengeluarkandatasecarastreaminguntukdiolahlebihlanjut.Perlumenjadicatatanbahwastream.Readabletidakakanmengeluarkandatajikalautidakdikehendaki.Nah...carauntukmendeteksidatastreaminginisudahsiapdikonsumsiataubelumadalahmelaluievent.
Eventyangdidukungolehclassstream.Readableadalahsebagaiberikut
Event:readableEvent:dataEvent:endEvent:errorEvent:close
Mungkinandabertanyakenapaserverfilestatisdiatasmemakaistream,bukankahmenyediakanfilesecaralangsungsajasudahbisa?jawabannyamemangbisa,tetapimungkintidakakanefisienkalaufileyangakandiberikankeclientmempunyaiukuranyangbesar.Cobalihatkodeberikut
varhttp=require('http');
varfs=require('fs');
varserver=http.createServer(function(req,res){
fs.readFile(__dirname+'/data.txt',function(err,data){
res.end(data);
});
});
server.listen(8000);
Jikafiledata.txtterlalubesarmakabufferyangdigunakanolehsistemjugabesardankonsumsimemorijugaakanbertambahbesarseiringsemakinbanyakpenggunayangmengaksesfileini.
JikaandainginlebihbanyakmendalamitentangNode.jsStreamsilahkanlihatresourceberikut(dalamBahasaInggris):
Node.jsAPIStreamStreamHandbook
ServerFileStatis
20
PemrosesanDataFormHTMLAplikasiwebmemperolehdatadaripenggunaumumnyamelaluipengisianformHTML.ContohnyasepertiketikaregistrasidimediasosialatauaktifitasupdatestatusdiFacebookmisalnyapastiakanmengisitextfielddankemudianmenekantombolsubmitataupunenteragardatabisaterkirimdandiprosesolehserver.
Datayangdikirimolehformbiasanyasalahsatudariduatipemimeberikut
application/x-www-form-urlencodedmultipart/form-data
Node.jssendirihanyamenyediakanparsingdatamelaluibodydarirequestsedangkanuntukvalidasiataupemrosesandataakandiserahkankepadakomunitas.
PemrosesanDataFormHTML
21
URLEncodeHanyaakandibahasuntuk2metodeHTTPyaituGETdanPOSTsaja.MetodeGETuntukmenampilkanformhtmldanPOSTuntukmenanganidataformyangdikirim
Oklangsungkitalihatkodeserversederhanauntukparsingdataformmelaluiobjekrequestdengandataformbertipeapplication/x-www-form-urlencodedyangmerupakandefaultdaritagform.
varhttp=require('http');
vardata=[];
varqs=require('querystring');
varserver=http.createServer(function(req,res){
if('/'==req.url){
switch(req.method){
case'GET':
tampilkanForm(res);
break;
case'POST':
prosesData(req,res);
break;
default:
badRequest(res);
}
}else{
notFound(res);
}
});
functiontampilkanForm(res){
varhtml='<html><head><title>DataHobiku</title></head><body>'
+'<h1>Hobiku</h1>'
+'<formmethod="post"action="/">'
+'<p><inputtype="text"name="hobi"></p>'
+'<p><inputtype="submit"value="Simpan"></p>'
+'</form></body></html>';
res.setHeader('Content-Type','text/html');
res.setHeader('Content-Length',Buffer.byteLength(html));
res.end(html);
}
functionprosesData(req,res){
varbody='';
req.setEncoding('utf-8');
req.on('data',function(chunk){
body+=chunk;
URLEncode
22
});
req.on('end',function(){
vardata=qs.parse(body);
res.setHeader('Content-Type','text/plain');
res.end('Hobiku:'+data.hobi);
});
}
functionbadRequest(res){
res.statusCode=400;
res.setHeader('Content-Type','text/plain');
res.end('400-BadRequest');
}
functionnotFound(res){
res.statusCode=404;
res.setHeader('Content-Type','text/plain');
res.end('404-NotFound');
}
server.listen(3003);
console.log('serverhttpberjalanpadaport3003');
UntukmengetestGETdanPOSTbisadilakukanmelaluicurl,browserataumelaluiguiPostman.
GET
URLEncode
23
modulequerystringdariNode.jsberfungsiuntukmengubahurlencodedstringmenjadiobjekJavaScript.Contohnya
querystring.parse('nama=lanadelrey&job=singer&album=borntodie&ultraviolence');
//returns
{nama:'lanadelrey',job:'singer',album:['borntodie','ultraviolence']}
URLEncode
25
MultipartDataParsingdataformdanfileyangdiuploadkeserverNode.jsadalahpekerjaanyangcukupsusahkalodikerjakansecaramanualataudariscratchkarenadisampingharusparsingdatabinaryyangberupafilejugaharusparsingdataform.
Protokoluntukmultipart/form-datadidefinisikansecaralengkapdiRFC2388.
MultipartData
26
ModuleNpmnicepeoplematter
npmmerupakanpackagemanageruntukNode.jsdanuntuknamanpmbukanlahsuatusingkatan.Hanyadalamwaktu2tahunsejakdireleasenyaNode.jskepublikjumlahmodulmelesatjauhbahkanhampirmenyamaimoduljavaataupunrubygems.
Grafikdiatasdidapatdarihttp://modulecounts.com.
BanyaknyapushmodulekerepositorinpmdapatdiartikanadanyakepercayaanpublikterhadapplatforminidanuntukkedepannyaNode.jsakanmenjadiplatformyangprospektifuntukberinvestasi.
Modulenpm
27
KonsepnpmmemakaisistemmodulCommonJSyangcukupmudahdalampenggunaanya.Sistemmoduliniakanmeng-exportobjekJavaScriptkevariabelexportsyangbersifatglobaldimodultersebut.
Sebagaicontoh
band.js
'usestrict';
functionBand(){}
Band.prototype.info=function(){
return'NamaBand:'+this.name;
}
Band.prototype.add=function(name){
this.name=name;
}
module.exports=newBand();
Untukpemakaiannyasepertidibawahini
app.js
varband=require('./band.js');
band.add('Dewa19');
console.log(band.info);
require()diatasadalahfungsisinkronyangmeloadpaketataumodullaindarisistemfile.
Konsep
28
PaketnpmSecaradefaultdatapaketnpmdisimpandiregistrynpmjs.org.Sehinggauntukmenginstallpaketnpmtertentuandabisamencaripaketinimelaluicommandnpmataulangsungmelaluiwebsite.
SejakversiNode.js0.6.3commandnpmsudahter-bundledenganinstallerNode.js.Untukmenginstallmodulnpmyangandabutuhkanketikmisalnya
npminstallexpress
perintahdiatasakanmendownloadpaketexpressdarihttp://npmjs.orgdansecaraotomatisakanmembuatdirectorynode_modules.
UntukmemakaimodulexpressinicukupdenganmembuatfileJavaScriptbarudiluardirektorinode_modulesdanloadmoduldengankeywordrequire.
varapp=require('express');
//kodelainnya
MembuatPaketnpmSebelummembuatpaketnpmpastikanfungsionalitasyangandacaritidakadadalamregistrynpm.Caranyayaituandabisamenggunakanperintah
npmsearch
ataudenganmemakaiwebsiteberikutnpmjs.org,node-modules.comataunpmsearch.com
Untukmembuatpaketnpmcaranyacukupmudah.Berikutalurumumuntukmembuatpaketnpmuntukdipublishkeregistrynpmjs.org.
Paketnpm
29
Secaragarisbesarprosespembuatanpaketnpmmenurutalurdiatasakandijelaskansebagaiberikut
Registrasi
Sebelumpublishkeregistrynpmjs.orgkitaharusregistrasidulumelaluiperintahberikut
Paketnpm
30
npmadduser
BuatProject
Untukmembuatprojectbarudarinollangkahpertamaadalahmembuatdirektori
mkdirnpmproject
Kemudianinisialisasiprojecttersebut
npminit
perintahdiatasakanmembuatfilepackage.jsonyangisinyaadalahinfodandependensiproject.Ikutisajatiappertanyaandanisiinformasisesuaidenganpaketyanginginandabuat.
Contohnyapadapaketsvhberikutini
package.json
{
"name":"svh",
"version":"0.0.7-beta",
"author":"EquanPr.",
"description":"Simplefileserverforhtml-javascriptwebclientappdevelopment",
"keywords":[
"process",
"reload",
"watch",
"development",
"restart",
"server",
"monitor",
"auto",
"static",
"nodemon"
],
"homepage":"https://github.com/junwatu/svh",
"bugs":"https://github.com/junwatu/svh/issues",
"main":"./lib/core.js",
"scripts":{
"test":"./node_modules/mocha/bin/mocha"
},
"dependencies":{
"async":"~0.2.9",
"chalk":"0.2.x",
"cheerio":"0.12.x",
Paketnpm
31
"commander":"2.0.x",
"compression":"^1.0.2",
"concat-stream":"1.0.x",
"express":"4.x",
"morgan":"^1.1.1",
"send":"^0.3.0",
"watch":"0.8.x",
"wordgenerator":"0.0.1"
},
"devDependencies":{
"gulp":"^3.5.6",
"gulp-uglifyjs":"^0.3.0",
"gulp-util":"2.2.14",
"mocha":"1.13.x",
"supertest":"0.8.x"
},
"repository":{
"type":"git",
"url":"http://github.com/junwatu/svh.git"
},
"bin":{
"svh":"./bin/svh"
},
"license":"MIT"
}
PublishLokal
Sebelumdipublishpastikanpaketandabisaberjalanataudigunakanpadakomputerlokal.Perintahberikutakanmenginstallpaketandasecaraglobaldikomputer.
npmpublish.-g
ataujikadiinginkanlinksimbolikbisamemakaiperintahnpmberikut
npmlink
PublishPublik
npmpublish
Untuklebihjelasnyasilahkankunjungidokumentasiuntukdevelopernpm.
Paketnpm
32
ExpressJSUntukmemudahkanpembuatanaplikasiwebandabisamenggunakanframeworkExpressJSdaripadaharusmenggunakanmodulehttpbawaanNode.js.Frameworkinimenawarkanbeberapafitursepertirouting,renderingviewdanmendukungmiddlewaredengankatalainandaakanbanyakmenghematwaktudalampengembanganaplikasiNode.js.
ExpressJSmerupakanframeworkminimalyangsangatfleksibel.AndabisamembuatwebserverHTML,serverfilestatik,aplikasichat,searchengine,sosialmedia,layananwebdenganaksesmelaluiRESTAPIatauaplikasihybridyaituselainpenggunamempunyaiaksesmelaluiRESTAPIjugamempunyaiakseskeHTMLpage.
ExpressJS
34
ServerFileSebelumnyabikinprojectkecildenganmengetikkanperintahberikutpadadirektoriproject
$npminit
danberikannamaprojectsebagaiserver-file-statik.Direktoriprojectdariserverfilebisadilihatpadasususantreedibawahini.
Susunanfiledandirektori
server-file-statis
├──package.json
├──app.js
├──node_modules
└──publik
├──index.html
DenganadanyanpminstalasiExpressJSsangatmudah,ketikperintahberikutpadadirektoriproject.
$npminstallexpress--save
Catatan:
PerintahdiatasakanmenginstallExpressJSdenganversiyangpalingterbaru(padasaatbukuiniditulisversiterbaruadalah4.x).Jikamembutuhkanversitertentucukupdenganmenambahkan'@'dannomerversiyangakandiinginkanseperticontohberikut
$npminstallexpress@3--save
UntukkedepannyabahasanmengenaiExpressJSiniakanmemakaiversi4.x.
Kode
ServerFile
35
JikaandaingatserverfileyangmemakaimodulhttppadababsebelumnyaberikutmerupakanversiyangmemakaiExpressJS
app.js
'usestrict';
varexpress=require('express');
varserver=express();
varlogger=require('morgan');
server.use(logger('dev'));
server.use(express.static(__dirname+'/publik'));
server.listen(4000,function(){
console.log('Serverfilesudahberjalanbos!');
});
SepertiyangdijelaskanpadababsebelumnyauntukmemakaimoduleNode.jsdigunakankeywordrequire.
Modulexpressakanmenanganitiaprequestdariuserdankemudianakanmemberikanresponseberupafileyangdiinginkan.Padakodediatasfileyangakandiberikankepenggunadisimpanpadafolderpublik.
ServerFile
36
MiddlewareFungsionalitasyangdiberikanolehExpressJSdibantuolehyangnamanyamiddlewareyaitufungsiasinkronyangbisamengubahrequestdanrespondiserver.
Padakodediatascontohmiddlewareyaitumodulmorgan.Carapemakaianmiddlewareyaitumelaluiapp.use().
Modulemorganmerupakanmoduluntukloggeryangberfungsiuntukpencatatantiaprequestkeserver.Pencatataniniatauistilahnyaloggingakanditunjukkandiconsoleterminal.
Untukmenginstallmoduliniketikperintahberikut
$npminstallmorgan--save
Middlewaremiddlewareinibisaandalihatdilinkberikut
https://github.com/senchalabs/connect#middleware
Middleware
37
AksesServerUntukmenjalankanserverfilestatikini
$nodeapp.js
Andabisameletakkanfileapasajapadadirektori'publik'.Untukmengaksesserveriniketikalamatberikutpadabrowser
http://localhost:4000
dansecaradefaultakanmenampilkanfileindex.htmldibrowser.
UntukmengaksesfileyanglainformatURLadalah
http://localhost:4000/[nama-file]
misalnyauntukmengaksesfileimg.jpg
AksesServer
38
ServerRESTFrameworkExpressJSsangatbanyakdigunakansebagaiaplikasiRESTful.Bagiandayangbelumtahu,RESTatauRepresentationalStateTransferadalaharsitekturyangdigunakandalamdesainaplikasinetwork.IdenyayaitudaripadamemakaitekniksepertiCORBA,SOAPatauRPCuntukmembuatWebServicelebihbaikjikamemakaiprotokolHTTPyanglebihmudah.
AplikasiRESTfulmemakairequestHTTPuntukoperasiCreate,Read,UpdatedanDeletedata.RESTitusendiribukanlahsuatustandardjaditidakadayangnamanyaspecdariW3C.Sehinggasangatmudahbagibahasapemrogramanuntukmenggunakanarsitekturini.KeuntunganlainnyayaitudenganarsitekturinibisadibangunberbagaimacamteknologikliensepertiwebataumobileataupundekstopuntukmengaksesaplikasiRESTfultersebut.
UntukcontohaplikasiRESTfulmemakaiExpressJSakandiberikanpadaBabPersonRESTAPI.
ServerREST
40
DatabaseBerkembangpesatnyakomunitasNode.jsmenyebabkandukunganpustakayangsemakincepatjuga.DenganwaktuyangrelatifcepatplatforminisekarangmendukungbanyaktipedatabasesepertiSQLite,MySQL,MongoDB,Redis,CouchDBdll.Dalambukuinihanyaakandibahasa3databasesajayaituSQLite,MySQLdanMongoDB.
Database
41
SQLiteMungkindatabaseinisudahtidakasinglagibagidevelopersepertiandakarenamemangbanyakdigunakandalamaplikasiportabledanembeddable.
KekuatanSQLitesecaragarisbesarsebagaiberikut
Serverless
SQLitetidakmemerlukanproseslainuntukberoperasisepertipadadatabaselainyangumumnyasebagaiserver.LibrarySQLiteakanmengaksesfiledatasecaralangsung.
ZeroConfiguration
Karenasifatnyabukanservermakadatabaseinitidakmemerlukansetuptertentu.Untukmembuatdatabasecukupsepertiketikamembuatfilebaru.
Cross-Platfrom
Semuadatatersimpanpadasatusistemfileyangbersifatcrossplatformdantidakmemerlukanadministrasi.
Self-Contained
LibrarySQLitesudahmencakupsemuasistemdatabasesehinggadenganmudahdapatdiintegrasikankeaplikasihost.
SmallRuntimeFootprint
UkurandefaultdariSQLiteinikurangdari1MBdanmembutuhkanhanyabeberapaMegabytememory.
Transactional
OperasitransaksikompatibeldenganACIDsehinggaamankalauharusmengaksesdatadariprosesbanyakthread.
Untukpenjelasanlebihdetil,silahkankunjungiwebsiteresmihttp://sqlite.org
SQLite
42
nodesqlite3KomunitasnodemenyediakanbanyaksolusiuntukmemakaiSQLitediplatformNode.js.Salahsatuyangpalingpopuleradalahmodulnode-sqlite3.
Instalnodesqlite3merupakanbindingmodulJavaScriptyangasinkronuntukdatabasesqlite3.
Untukpenginstalanmoduliniketikperintahberikut
$npminstallsqlite3--save
CRUDOperasidatabasesepertiCreate,Read,UpdatedanDeleteuntukdatabaseSQLitesangatmudahsepertipadacontohberikut
app.js
/**
*AksesSQLite3
*/
varsqlite=require('sqlite3').verbose();
varfile='film.db';
vardb=newsqlite.Database(file);
varfs=require('fs');
//SampleData
varfilm={
judul:"Keramat",
release:"2009",
imdb:"http://www.imdb.com/title/tt1495818/",
deskripsi:"Filmhorrorpalinghorror!"
}
varfilmUpdate={
id:1,
deskripsi:"BestIndonesianHorrorMovie."
}
//SQLStatement
varCREATE_TABLE="CREATETABLEIFNOTEXISTSfdb(idINTEGERPRIMARYKEYAUTOINCREM
NodeSqlite3
43
ENT,judulTEXTNOTNULL,releaseTEXTNOTNULL,imdbTEXT,deskripsiTEXT)";
varINSERT_DATA="INSERTINTOfdb(judul,release,imdb,deskripsi)VALUES(?,?,?,
?)";
varSELECT_DATA="SELECT*FROMfdb";
varUPDATE_DATA="UPDATEfdbSETdeskripsi=$deskripsiWHEREid=$id";
//RunSQLoneatatime
db.serialize(function(){
//Createtable
db.run(CREATE_TABLE,function(err){
if(err){
console.log(err);
}else{
console.log('CREATETABLE');
}
});
//Insertdatawithsampledata
db.run(INSERT_DATA,[film.judul,film.release,film.imdb,film.deskripsi],functio
n(err){
if(err){
console.log(err);
}else{
console.log('INSERTDATA');
}
});
//Queryalldata
selectAllData();
//Updatedata
db.run(UPDATE_DATA,{$deskripsi:filmUpdate.deskripsi,$id:filmUpdate.id},functi
on(err){
if(err){
console.log(err);
}else{
console.log('UDATEDATA');
}
});
selectAllData();
db.run('DELETEFROMfdbWHEREid=$id',{$id:1},function(err){
if(err){
console.log(err)
}else{
console.log("DELETEDATA");
};
})
});
NodeSqlite3
44
functionselectAllData(){
db.each(SELECT_DATA,function(err,rows){
if(!err){
console.log(rows);
}
})
}
Aplikasidiatasakanmembuattabelfdb,memasukkandatabarukemudiandatatersebutakandiupdatedanterakhirakandihapus.
ContohdiatasmemakaiAPIberikutini
db.serialize()
db.run(operasi_sqlite,callback)
Denganmemakaifungsidb.serialize()makaeksekusisqlakandieksekusisecaraserialatauberurutandanoperasiSQLapasajabisadieksekusiolehnode-sqlite3denganmemakaimetodedb.run()tersebut.
PenjelasanAPIlebihlanjutuntukNodeSQLitebisadilihatpadalinkberikut
https://github.com/mapbox/node-sqlite3/wiki/API.
NodeSqlite3
45
EnkripsiKalauandamemakaiSQLitedanmembutuhkansupayadatabaseiniterenkripsimakaberuntunglahkarenanodesqlite3mendukungpenggunaandatabaseSQLiteyangterenkripsi.
EnkripsiyangdidukungolehSQLiteyaitumelaluiekstensisqlcipher.Sqlciphermerupakanekstensisqliteyangmendukungenkripsi256bitAES.Ekstensiinibisadididownloadmelaluiwebsiteberikut
https://github.com/sqlcipher/sqlcipher
Enkripsi
46
sqlcipherInstalasiekstensiinisangatmudahyaitujikaandaberadadalamlingkunganLinux
$sudoapt-getinstalllibsqlcipher-dev
Kemudiankompilasiulangnode-sqlite3denganperintahberikutini
$npminstallsqlite3--build-from-source--sqlite_libname=sqlcipher\
--sqlite=/usr/
Untukmenggunakanfiturenkripsiiniperuditambahkanbeberapabariskodeberikutpadaaplikasinode-sqlite3.
//encryptdatabase
db.run('PRAGMAkey="passwordmu!"');
PadacontohCRUDnode-sqlite3padabagiansebelumnyakodediatasbisadituliskansebelumoperasiCRUDataupadasaatinisialisasi.
...
//RunSQLoneatatime
db.serialize(function(){
//encryptdatabase
db.run('PRAGMAkey="passwordmu!"');
//Createtable
db.run(CREATE_TABLE,function(err){
if(err){
console.log(err);
}else{
console.log('CREATETABLE');
}
});
...
BandingkanjikaSQLitetidakmemakaienkripsi,andabisamenggunakanSQLiteBrowseratautoolhexdumppadaLinux
Enkripsi
47
danjikaSQLitememakaienkripsibisadilihatdariscreenshotdibawahinibahwaisidaridatabasemenjadi"meaningless".
Enkripsi
48
MySQLKalauandaterbiasadenganbahasapemrogramanPHPmakapastisudahtidakasinglagidengandatabaserelasionalyangpalingbanyakdipakaisaatiniyaituMySQL.
MySQL
50
NodeMySQLImplementasidriverdariMySQLuntukplatformNode.jssudahsangatmaturesepertimodulnode-mysqldihttps://github.com/felixge/node-mysql/
InstalasiSepertibiasauntukmenginstallmodulinidansecaraotomatismenyimpannama&versimoduldifilepackage.jsonyaitudenganmemakaiperintahberikut
$npminstall--savemysql
KoneksiSederhanaUntukmembuatkoneksikedatabaseMySQLsalahsatucaranyaadalahdenganmenggunakanmetodeconnection.connect()
NodeMySQL
51
//app.js
varmysql=require('mysql');
/**
*Settingopsidariconnection,
*lihathttps://github.com/felixge/node-mysql/
*/
varconnection=mysql.createConnection({
host:'localhost',
user:'root',
password:''
});
//MembukakoneksikedatabaseMySQL
connection.connect(function(err){
if(err){
console.log(err);
}else{
console.log('Koneksidenganid'+connection.threadId);
}
});
//Querybisadilakukandisini
//Menutupkoneksi
connection.end(function(err){
if(err){
console.log(err);
}else{
console.log('koneksiditutup!');
}
});
QueryIstilahquerymungkinmenurutmindsetumumartinyaadalahmengambildatadaridatabasetetapidalammodulnode-mysqliniuntukmembuatdatabaseatauschemajugadidefiniskansebagaiquery.Adabeberapabentukfungsiuntukwrapperquery
connection.query(sqlString,callback)
DenganmemakaistatemenSQLkitabisamembuatschemadatabaseebooksepertiberikut
NodeMySQL
52
varcreate_db='CREATEDATABASEIFNOTEXISTSebook'
connection.query(create_db,function(err,result){
if(err){
console.log(err);
}else{
console.log(result);
}
)
connection.query(sqlString,value,callback)
Misalnyauntukmenyimpandatasemuajudulbukupadadatabaseebook
varebook={
id:1,
title:'WiroSablengPendekarKapakMautNagaGeni212:BatuTujuhWarna',
pengarang:'BastianTito'
}
varinsert_sql='INSERTINTOebookSET?';
connection.query(insert_sql,ebook,function(err,result){
err?console.log(err):console.log(result);
})
KalaudibutuhkanescapingvaluesebelumdimasukkankedatabaseMySQLbisamemakaimetode.escape()ataupakeplaceholder?.
varebook={
id:1,
title:'WiroSablengPendekarKapakMautNagaGeni212:BatuTujuhWarna',
pengarang:'BastianTito'
}
varinsert_sql='UPDATEebookSETtitle=?WHEREid=?';
connection.query(insert_sql,[ebook.title,ebook.id],function(err,result){
err?console.log(err):console.log(result);
})
connection.query(options,callback)
Bentukwrapperqueryyangterakhirinicukupringkas.Sesuaikansajamanabentukwrapperyangsesuaidengankebutuhananda.
NodeMySQL
53
varebook={
sql:'INSERTINTOebookSETpengarang=?',
timeout:14000,
values:['PramoedyaAnantaToer']
}
connection.query(ebook,function(err,result,fields){
if(err){
console.log(err);
}else{
console.log(result);
}
})
MetodequeryinisangatfleksibeldanpadaintinyakitabisamemakaistatemenSQLyangbiasadipakaiuntukquerydatadiMySQL.Jadipenggunaandarimodulnpminisebenarnyacukuplahmudah.
UntukpenggunaanmodulnpminilebihlanjutsilahkankunjungiGithubnode-mysqldanuntukcontohaplikasiyangmemanfaatkandatabaseinibisadilihatpadababPengubahGambarPNGKeDataURI.
NodeMySQL
54
MongoDBKalauandasudahterbiasamemakaidatabaserelasionalsepertiMySQLmungkindiperlukansedikitperubahanmindsetuntukmengenaltipedatabaseyangnamanyaNoSQL.Sepertiartidarinamanya,databaseinimerupakandatabaseyangtidakmemakaibahasaSQLquerydatatapibisasecaralangsungmenggunakanbahasapemrogramanclientsebagaicontohadalahMongoDB.
DatabaseNoSQLsepertiMongoDBmenyimpandatasebagaidokumenyangschema-lessyangartinyayaitudatayangdisimpanmempunyaikey-valueyangtidakterikatataubebas.AndabisamembayangkannyasebagaidataJSONyangtersimpandidatabase.
KlienbisaberinteraksilangsungdengandatabaseMongoDBdenganmenggunakanshellJavaScriptmongountukadministrasidanquerydata.Sebagaicontohjikakitainginmembuatsampledatasebanyak100dicollectionsamplemakaperintahdalamshelladalahsepertiberikut,
MongoDB
55
$mongo
MongoDBshellversion:2.6.9
connectingto:test
>usesample;
switchedtodbsample
>for(vari=0;i<100;i++){db.sample.insert({band:"Dewa"+i})};
WriteResult({"nInserted":1})
>db.sample.count()
100
>db.sample.find();
{"_id":ObjectId("55cf520e2dd317a13673d11b"),"band":"Dewa0"}
{"_id":ObjectId("55cf520e2dd317a13673d11c"),"band":"Dewa1"}
{"_id":ObjectId("55cf520e2dd317a13673d11d"),"band":"Dewa2"}
{"_id":ObjectId("55cf520e2dd317a13673d11e"),"band":"Dewa3"}
{"_id":ObjectId("55cf520e2dd317a13673d11f"),"band":"Dewa4"}
{"_id":ObjectId("55cf520e2dd317a13673d120"),"band":"Dewa5"}
{"_id":ObjectId("55cf520e2dd317a13673d121"),"band":"Dewa6"}
{"_id":ObjectId("55cf520e2dd317a13673d122"),"band":"Dewa7"}
{"_id":ObjectId("55cf520e2dd317a13673d123"),"band":"Dewa8"}
{"_id":ObjectId("55cf520e2dd317a13673d124"),"band":"Dewa9"}
{"_id":ObjectId("55cf520e2dd317a13673d125"),"band":"Dewa10"}
{"_id":ObjectId("55cf520e2dd317a13673d126"),"band":"Dewa11"}
{"_id":ObjectId("55cf520e2dd317a13673d127"),"band":"Dewa12"}
{"_id":ObjectId("55cf520e2dd317a13673d128"),"band":"Dewa13"}
{"_id":ObjectId("55cf520e2dd317a13673d129"),"band":"Dewa14"}
{"_id":ObjectId("55cf520e2dd317a13673d12a"),"band":"Dewa15"}
{"_id":ObjectId("55cf520e2dd317a13673d12b"),"band":"Dewa16"}
{"_id":ObjectId("55cf520e2dd317a13673d12c"),"band":"Dewa17"}
{"_id":ObjectId("55cf520e2dd317a13673d12d"),"band":"Dewa18"}
Type"it"formore
>
UntuklebihjelasnyajikaandatertarikuntukbermainmaindenganterminalMongoDBsilahkankunjungidokumentasinya.
SebelumkitalanjutkankekoneksiNode.jsdanMongoDB,perludiingatbeberapakonseppentingdariMongoDB
Collection
Collectionadalahkumpulandaridocument,analoginyawalaupunkurangtepatsebenarnyabisadibilangsepertitabelkalodalamdatabaserelasional.
Document
MongoDB
56
DocumentitusendiriadalahdatayangtersimpandidatabaseNoSQLdandidefinisikanolehyangnamanyaSchema.
Schema
SebelumnyadikatakanbahwaNoSQLmenyimpandatayangschema-less,memangbenartapitetapuntukmenyimpansuatudokumendidatabasebiasanyaaplikasibekerjadenganmodeldatatertentumisalnyauntukdataPersonbisamempunyaikey-valuesepertiberikut
{
nama:"KeboIjo",
email:"mbolang@kebo.xyz",
username:"obek_seloso"
}
MongoDB
57
NodeMongoDBMongoDBmenyediakandriverresmiuntukplatformNode.js.Modulenpminitersediadilinkberikuthttps://www.npmjs.com/package/mongodbdandapatdenganmudahdiinstallmelaluinpm
$npminstall--savemongodb
PenulismengasumsikanbahwaMongoDBsudahterinstaldanberjalanpadasistem.Untukmemulaikoneksidapatdenganmudahdilakukansepertiscriptberikutini,
app.js
varMongoClient=require('mongodb').MongoClient;
varMONGODB_URL='mongodb://localhost:27017/sample';
MongoClient.connect(MONGODB_URL,function(err,db){
err?console.log(err):console.log('KoneksikeMongoDBOk!');
db.close();
});
MongoDBakanmembuatdatabasebarujikadatabasetersebuttidakada,sepertihalnyadengandatabasesamplepadakodediataskarenasebelumnyadatabaseinitidakadamakasecaraotomatisMongoDBakanmembuatnya.BentukumumURIuntukkoneksikeMongoDBadalahsepertiberikut
mongodb://<username>:<password>@<localhost>:<port>/<database>
JalankanapikasiditerminaldanjikatidakadamasalahmakaakanmunculpesanpadakonsolbahwakoneksikeMongoDBtelahsukses.
$nodeapp.js
KoneksikeMongoDBOk!
BerikutnyaakankitalakukanoperasidasaruntukMongoDByaituCRUDtapisebelumnyakitabuatschematerlebihdahulu.
person.js
NodeMongoDB
58
functionPersonSchema(data){
this.nama=data.nama;
this.email=data.email;
this.username=data.username;
};
module.exports=PersonSchema;
SchemadiatasmerupakanmodeldatasederhanayangdituliskandalamobjectJavaScriptdantanpabuilt-intypecastingataupunfiturvalidasi.Jikaandamembutuhkanpemodelandatayanglebihhandaldanlebihbaik,makapakailahpustakaODM(Object-DocumentModeler)sepertiMongoose.
DriverNodeMongoDBmenyediakanAPIyanglengkapuntukbekerjadengandatabaseini.SilahkanlihatlinkberikutuntukmelihatlebihlengkaptentangAPIini
http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html#insert
InsertUntukmemasukkandokumenbisamemakaimetodeinsertOne()untukmemasukkansatudokumen
app.js
NodeMongoDB
59
/**
*BalajarNode-MongoDB
*
*
*MIT
*EquanPr.2015
*/
varPersonSchema=require('./person.js');
varMongoClient=require('mongodb').MongoClient;
varMONGODB_URL='mongodb://localhost:27017/sample';
varperson=newPersonSchema({
nama:'KeboIjo',
email:'kebo@ijo.xyz',
username:'obek_rebo'
});
MongoClient.connect(MONGODB_URL,function(err,db){
err?console.log(err):console.log('KoneksikeMongoDBOk!');
db.collection('persons').insertOne(person,function(err,result){
if(err){
console.log(err);
}else{
console.log(result);
}
db.close();
})
});
Secaraotomatisoperasiinsertiniakanmenghasilkanprimarykey_idyangunikyaituberupaObjectId.Yangmembedakan_idinidenganidpadadatabaseyanglainadalahdenganObjectIdbisadidapatkankapandatainidimasukkanmelaluipemakaianmetodegetTimestamp().
$mongo
MongoDBshellversion:2.6.9
connectingto:test
>_id=ObjectId()
ObjectId("55d81f48bb934a51424dbd37")
>ObjectId("55d81f48bb934a51424dbd37").getTimestamp();
ISODate("2015-08-22T07:05:44Z")
>
NodeMongoDB
60
Jikaandamempunyaibanyakdokumen,untukmemasukkandokumen-dokumentersebutkecollectionpersonsandabisamemakaimetodeinsertMany().
UpdateOperasiupdatedatajugacukupmudahapalagijikaandasangatpahamntentangMongoDB.Untukmeng-updatedatabisadilakukanmelaluimetodeupdateOne()atauupdateMany().
app.js
varPersonSchema=require('./person.js');
varMongoClient=require('mongodb').MongoClient;
varMONGODB_URL='mongodb://localhost:27017/sample';
varperson=newPersonSchema({
nama:'KeboIjo',
email:'kebo@ijo.xyz',
username:'obek_rebo'
});
MongoClient.connect(MONGODB_URL,function(err,db){
err?console.log(err):console.log('KoneksikeMongoDBOk!');
db.collection('persons').insertOne(person,function(err,result){
if(err){
console.log(err);
}else{
console.log('Simpandatapersonok!');
//updatedata
varpersonUpdate={
nama:'SukatTandika'
}
db.collection('persons').updateOne({nama:person.nama},personUpdate,funct
ion(err,result){
if(err){
console.log(err);
}else{
console.log('Datapersonberhasildimodifikasi!');
}
db.close();
})
}
})
});
MetodeupdateOne()mempunyaibeberapaargumensepertiberikut
NodeMongoDB
61
updateOne(filter,update,options,callback)
Untukdataupdateandabisamemakaioperatorseperti$setcontohnyasepertiberikutini
db.collection('persons').updateOne({nama:person.nama},{$set:{nama:'Angel'}},functi
on(err,result){
if(err){
console.log(err);
}else{
console.log('Datapersonberhasildimodifikasi!');
}
db.close();
})
daribeberapaoptionsyangterpentingadalahkeyupsertyaituupdateinsertdanjikaoptioninidiberikanmakajikadatayangakandi-updatetidakadamakaMongoDBsecaraotomatisakanmembuatdatayangbaru.UntuklebihjelasnyaandabisamelihatdokumentasidariAPIupdateOne().
QueryQuerydatapadadatabaseMongoDBdapatdenganmudahdilakukandenganmemakaimetodefind(),sebagaicontohuntukmenemukandatapersonpadacollectionpersons
NodeMongoDB
62
MongoClient.connect(MONGODB_URL,function(err,db){
if(!err){
findPerson({nama:'MorbidAngel'},db,function(err,doc){
if(!err){
console.log(doc);
}else{
console.log(err);
}
db.close();
});
}else{
console.log(err);
}
});
functionfindPerson(filter,db,callback){
varcursor=db.collection('persons').find(filter);
cursor.each(function(err,docResult){
if(err){
callback(err,null);
}else{
if(docResult!=null){
console.log(docResult);
callback(null,docResult);
}else{
callback(null,'empty!');
}
}
})
}
Denganmetodefind()andabisamemakaioperatorqueryseperti$lt,$gt,operatorkondisiAND,ORdll.UntuklebihlengkapnyasilahkanlihatdokumentasiquerydaridrivernodeMongoDB.
DeleteUntukmenghapusdataandabisamenggunakanfungsideleteOne()ataudeleteMany().Misalnyauntukmenghapussemuadatapadacollectionpersonsandabisamenggunakanemptyobject{}sebagaiquery.
NodeMongoDB
63
functiondeleteAllPerson(db,callback){
db.collection('persons').deleteMany({},function(err,rec){
if(!err){
callback(null,rec.result.n);
}else{
callback(err,null);
}
})
}
ataujikainginmenhapussatudatapadacollectionperson
fucntiondeletePerson(filter,db,callback){
db.collection('persons').deleteOne(filter,function(err,rec){
if(!err){
callback(null,rec.result.n);
}else{
callback(err,null);
}
})
}
DuafungsiinibisaandalihatsecaralengkappadadokumentasiAPIMongoDB.
NodeMongoDB
64
MongooseSepertidikatakansebelumnyauntukmemudahkanpemodelandatadiMongoDBandabisamemakaipustakaMongoose.MeskipunsebenarnyaMongoosememakaiobjekJavaScriptbiasadanmendukungbanyakmetodequerydatatetapiyangpalingmembedakanadalahMongoosemendukungschematypedanvalidasidilevelschema.
data:{type:schemaType}
SchemaTypeAdabeberapaschematypeyangdidukungolehpustakainiyaitu
StringNumberDateBooleanBuffer(untukdatabinarymisalnyagambar,mp3dll.)Mixed(datadengantipeapasaja)ArrayObjectId
PemodelanDataLalubagaimanaMongoosememodeldata?ambilcontohmisalnyadalampengembanganaplikasi,datayangakandipakaisepertiberikut
varlokasiWisataKotaBatu=[{
nama:'BatuNightSquare',
alamat:'Jl.Orooroombo13,Tlekung'
rating:3,
fasilitas:['Wahanabermain','Rollercoaster','Tamanlampion']
}]
DaridatadiatasdenganmemakaiMongoosesangatmudahuntukditerjemahkankeskemadantipedatauntuktiapfield
Mongoose
65
varlokasiWisataKotaBatuSchema=newmongoose.schema({
nama:String,
alamat:String,
rating:Number,
fasilitas:[String]
})
Bagaimanadenganvalidasidata?.Jikaandalihatfielddataratingdiatasdanumumnyamempunyainilaiantara0-5danjikasecaradefaultdiberinilai0makaskemaratingakanmenjadi
rating:{type:Number,'default':0}
Andajugabisamemakaikeyrequireduntukmenandakanbahwafielddatatersebutbersifatwajibadamisalnya
nama:{type:String,required:true}
UntuklebihjelasnyasilahakanlihatdokumentasidariValidatorsMongoose.
Aplikasinode.jsdengandatabaseMongoDByangmemakaipustakaMongoosedapatdikatakanmempunyaihubunganrelasisatu-satuartinyadenganmemakaimodelMongooseberartisecaralangsungaplikasiakanmemakaidatapadaMongoDB.
KalaumisalnyaandabekerjadengandatabaserelasionalMySQLmakaandaakanmemakaibahasaSQLsepertiINSERTINTOtableVALUES(field1=data)untukmemasukkandatasedangkansepertiandaketahuijikadengandatabaseNoSQLuntukmenyimpanmodelobjectcukupdenganmemakaimetodemisalnyamodel.save().DalamMongooseuntukmemakaimodelyangtelahmempunyaischemasepertidiatas
varLokasiModel=mongoose.model('Lokasi',lokasiWisataKotaBatuSchema,'lokasiWisataBa
tu')
KodediatasmemberiartibahwaaplikasiakanmemakaimodelLokasidenganschematypeyangtelahdidefinisikansebelumnyayaitulokasiWisataKotaBatuSchemadanmodeliniakandisimpanpadakoleksidatadiMongoDBdengannamakoleksiadalahlokasiWisataBatu.
UntukmemakaimodelLokasicaranyaadalahdenganmenciptakaninstancedarimodeltersebut
Mongoose
66
varlokasiModel=newLokasiModel()
lokasiModel.nama='MuseumAngkut'
lokasiModel.alamat='Jl.Kembar11'
lokasiModel.rating=5
lokasiModel.fasilitas=['Restoran','Parkirluas']
KemudianuntukmenyimpandatatersebutkedalamdatabaseMongoDB
lokasiModel.save(function(err){
if(!err)console.log('DataDisimpan!')
})
Cukupmudahbukandanmemangpustakainibertujuanuntukmemudahkandeveloperdalampemodelandataterutamajikadatayangakandimodelmempunyaistrukturyangrumitmisalnyanesteddocument.Untuklebihlengkapnyasilahkanandamengunjungisitusresmimongoosejs.com.
ProjekBagiandayangsudahmengertigambaranumumdaripustakaMongooseinisilahkanmengutakatikcontohprojeksederhanayangmemakaiframeworkExpressJSdanMongoose,PersonRESTAPI.
Mongoose
67
TestingPerangkatlunaktidakadayangsempurnadanpastimempunyaibugs.Salahsatucarauntukmenguranginyaataumencegahnyauntukmunculdikemudianhariadalahdenganjalanmelakukanpengetesan.Pengetesanmemberikankeyakinanpadadeveloperbahwaperangkatlunakbekerjasebagaimanamestinyadanjikaadaperubahanmisalnyapenambahanataupenguranganfiturdipastikanbahwapengetesanakanselaluberhasil.
AdabanyaktipepengetesantetapidalampengembanganaplikasiwebadaduatipepengetesanyangpentinguntukdiketahuiyaituUnitTestingdanAcceptanceTesting.
UnitTestingUnitTestingdilakukanlangsungpadalevelkodeaplikasiyaitupadafungsiataumetodedanadaduametodologiyangseringdigunakanyaituTDDdanBDD.DalamJavaScripttersediabanyakpustakayangdibuatuntukpengetesansepertimoduleassertbawaandariNode.js,Nodeunit,Mocha,Jasminedll.
TestDrivenDevelopment(TDD)
IstilahTDDinimenjadisangatkerenbeberapatahunbelakanganini.KonsepTDDadalahmelakukanpengetesanterlebihdahulubarukemudianmenuliskodedariaplikasi,jadimindsetdaripembuatanperangkatlunakdibalikkalodalampengembanganperangkatlunakyangkonvensionalalurnyayaitumenuliskodeterlebihdahulubarukemudianmenuliskodeuntukpengetesansedangkandalamTestDrivenDevelopmentprosesinidibalik.
Kelemahanpengetesaniniadalahpadaprosesawalbiasanyadibutuhkanwaktuyangrelatiflebihlamauntukmengembangkanaplikasikarenaharusmenuliskodepengetesanterlebihdahulutetapikeuntunganjangkapanjangnyayaituaplikasiyangdihasilkanbiasanyamempunyaibugsyanglebihsedikit.
BehaviorDrivenDevelopment(BDD)
PengetesansecaraBDDmemakaibahasaataumetodepengetesanyanglebihramahyaitudenganmelakukanpengetesandengancaraataualursepertiuserstorysehinggapengetesaninirelatiflebihpopulerkarenasecarabahasamenjembataniataumemungkinkankolaborasiantaradeveloperdanklien.AdabanyakpustakapengetesanyangmemakaiBDDsepertiMocha,Jasmin,Vowsdll.SebagaigambarancontohuntukpustakaMochamisalnya
Testing
68
describe('Uploadfile',function(){
it('Harusbisamenerimafilejpeg',function(){
//testingdisini
})
it('Harusbisamenerimafilepng',function(){
//testingdisini
})
it('Harusbisamenerimafilexcf',function(){
//testingdisini
})
})
KalauditerjemahkansecarabahasamanusiamakakodetestingBDDdiatasakanmudahdibacayaituUploadfileharusbisamenerimafilejpeg,pngatauxcf.
AcceptanceTestingUntukpengetesandariantarmukaaplikasiwebbesertafungsinyacontohnyasepertipengetesanpenekananbuttonapakahberfungsidenganbaikatautidakadalahtermasukdariAcceptanceTesting.TestinginibisadilakukandenganmemakaibantuanbrowserdandenganmunculnyaheadlessbrowsersepertiPhantomJSmemungkinkanpengetesandilakukansecaraterintegrasidengankodeback-end.
Catatanpentingdaritestingadalahpengetesandiusahakanberjalansecaraautomatissehinggajikaadakesalahanyangterjadimakadeveloperbisasegeramemperbaikinya,makadariitutestingpastimempunyaiyangnamanyainfolaporanentahituberupafile,outputterminalatauantarmukaberupaweb.Padaprosespengembanganperangkatlunakmodern,automasitestingmerupakanbagianyangsangatpenting.
DalambukuinipengetesanakandibatasipadapengetesanaplikasiwebkhususnyaaplikasiNode.jsdenganRESTdenganmemakaiMocha.
Testing
69
PengetesanRESTKitaambilcontohserveryangdibuatdenganExpressJS.ServerdibawahiniakanmengeluarkandataberupaJSONpadaURL/.
varexpress=require('express')
varapp=express()
app.get('/',function(req,res){
res.json({
message:'hello'
})
})
module.exports=app
LalubagaimanacaramengetestURL/diatas?denganmemakaiMocha,moduleassertdanmodulSupertestyaitumodulnpmyangkhususuntukmengetestserverHTTP.MochatermasukpustakapengetesanyangbisadipakaisecaraBDDataupunTDD.PustakainisecaradefaultmemakaistyleBDDdanmetodeyangyangbiasadipakaiadalahdescribe&it.
varmocha=require('mocha')
varrequest=require('supertest')
varassert=require('assert')
varapp=require('../app')
describe('TestRESTAPI',function(){
describe('GET/',function(){
it('shouldreturnjsonwithkey"message"andvalue"hello"',function(done){
request(app).get('/')
.set('Accept','application/json')
.expect('Content-Type',/json/)
.expect(200)
.expect(function(res){
assert.equal(res.body.message,'hello')
})
.end(function(err,res){
if(err)returndone(err)
done()
})
})
})
})
REST
70
PerluandaingatbahwasupertestakansecaraotomatismenjalankanserverExpressJSdanmengalokasikanportsehinggaandatidakperlumejalankanserversecaralangsung.
request(app)
Kalauditerjemahkandalambahasamanusiakodediatasakanmengetestbeberapakondisiyaitu
expect('Content-Type',/json/)
kodediatasartinyadiharapkanresponsedariGETuntukURL/adalahbertipejson
expect(200)
kodediatasartinyaresponsecodedarirequestHTTPharusmempunyaikode200.
expect(function(res){
assert.equal(res.body.message,'hello')
})
dankodediatasartinyadiharapkanbahwaresponsebodydenganfieldmessagemempunyaivaluehellodantentusajaandabisamenambahkanbanyakkondisiuntukpengetesanyanglebihdetil.
Untukmelakukanpengetesancukupdenganmenginstaldanjalankanmochamakasecaraotomatismochaakanmenjalankanberkasberkaspengetesanyangberadapadafoldertest.
$npminstall-gmocha
REST
71
Sebenarnyabanyakyangbisadijelaskantentangpengetesandansudahbanyakresourceonlinediluarsanayangmembahastentanginitapiyangperluandaingatadalahpastikanpengetesandimasukkandalamalurkerjadalampengembanganperangkatlunakyangsedangandakerjakan.
REST
72
AutomasiDalamprakteknyabiasanyatestinginidilakukansecaraotomatismisalnyajikaandamemakaiGithubdalampengembanganperangkatlunakopensourcemakaandabisamemakaiserverTravisyangdengansettingkonfigurasitertentuakanmenjalankanpengetesanjikaandamenge-pushkodekerepositoryGithubatauandabisamemakaibuildserveryangadadiluaransepertiJenkins,Bamboo,TeamCitydll.
TravisJikaandamemakaiGithubdanmenggunanakanTravismakasecaradefaultservertravisiniakanmenjalankancommand
$npmtest
sehinggadalampackage.jsonyangandapushkeGithubandaperlumenulisscriptuntukpengetesanmisalnyajikamemakaiMocha
"scripts":{
"test":"mocha"
}
.travis.yml
UntuksettingTravisandacukupmembuatfile.travis.ymlpadafolderprojekmisalnyasepertidibawahini(contohsourcecodeprojektestadadisini)
.
├──app.js
├──.travis.yml
├──node_modules
├──package.json
└──test
└──app.test.js
DenganisifiletersebutadalahversidariNode.jsdimanatestakandijalankan.MisalnyauntukmenjalankanpengetesanNode.jsversi4.1dan4.0
Automasi
73
language:node_js
node_js:
-"4.1"
-"4.0"
KemudianandaperlumengaturkonfigurasirepodiGithub(TestingLearn).SupayaGithubbisamemakaiservicedariTravismakaandaperlumeengubahkonfigurasirepo(MasukkemenuSettings)
EnableBuild
SupayabuildselaludijalankanolehTravismakaandaharusmeng-ON-kantombolenableditravis-ci.orgpadarepoyangandainginkan.
TestBuild
Automasi
74
BuildakandijalankanolehTravissetiapadakodebarudiGithubatauandabisamenggunakantombolTestServicepadaSettings->Webhooks&servicesuntukforcebuild.
Notifikasi
NotifikasiTravisbisadiintegrasikandenganSlack,Email,dllataubiasanyadengangambarstatusdiREADMErepo.UntukkonfigurasigambarstatuskliktombolBuild/PassingdisebelahnamarepodiTravisdancopypastekeREADMErepodiGithub.
SehinggajikaandamembukarepodiGithubmakaakanmunculgambarstatusyangapakahbuildsuksesataudalamstatuserror.
Automasi
75
ToDataURIAplikasiiniadalahaplikasiNode.jsCLIyangmengubahgambarpngkeformatdataURIdankemudianmenyimpandatatersebutkedatabaseMySQL.Prosesinibisadigambarkansepertigambaralurdibawahini.
DataURIBagiyangbelumtahuDataURIadalahsalahsatucarauntukmeng-embeddatasecarainlinealih-alihharusmengambildatatersebutdariresourceluar.DatayangakandiubahkeDataURIdisinibisaberupaimage,filecsvdll.Untukaplikasiinihanyadibatasiuntukgambarberformatpng.
FormatDataURIadalahsepertiberikutini
data:[<MIME-type>][;charset=<encoding>][;base64],<data>
Umumnyauntukgambarjenisencodingyangdipakaiadalahbase64.SebagaicontohnyalihatformatgambarpngyangtelahdirubahkeDataURIberikutini
ToDataURI
77
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAAABGdBTUEAANjr9RwU
qgAAACBjSFJNAABtmAAAc44AAPXqAACD0AAAfHIAAN7iAAAyWgAAI0zujJoVAAADAFBMVEXW1tYxLS6EgYKtrK
y7uro/OzxoZWZMSUrk5OR2c3SfnZ7y8vJaV1iRj5DJyMgjHyD///8RERESEhITExMUFBQVFRUWFhYXFxcYGBgZ
GRkaGhobGxscHBwdHR0eHh4fHx8gICAhISEiIiIjIyMkJCQlJSUmJiYnJycoKCgpKSkqKiorKyssLCwtLS0uLi
4vLy8wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6Ojo7Ozs8PDw9PT0+Pj4/Pz9AQEBBQUFCQkJDQ0NE
RERFRUVGRkZHR0dISEhJSUlKSkpLS0tMTExNTU1OTk5PT09QUFBRUVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWV
laWlpbW1tcXFxdXV1eXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5v
b29wcHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGCgoKDg4OEhI
SFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZma
mpqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6
+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTF
xcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2t
rb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w
8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7///8EKbe0AAAACXBIWXMAAAsTAA
ALEwEAmpwYAAAB/0lEQVRIx62W2W7sIBBE2Rf3UvX/X5sHYyczyb2eGRnJEjZw6C4KTOD7pQAtXHUKH4AthRab
ldvBIQZmm7GHm8HcOiVTErabweyF6mSJ82bwNjl2Uexe8IiyVxzlVjDnoYEdU9wEFoxVqdut4FFPU9dbwTmdsc
f8Cjj/6BXOwUzP85vxWLXZXwGbSRAnGQZdJZBOuqhzBJLBz34jLvL42xi/wB5T69JTS66uJEZPKXpLSaWntBR1
LdAj5JjlFbCS2BLpC2yJ1C2qxtx6OzwQm9YVqWway4vgolKmq1dxZJVRcx9issmoa0CJW+hnoF7n5eKFRCqzzh
ASTbMya5rBWyssTX+69nt1pfR2j93W4KWAIWq6AAc/8nN/45diVxpPIO6btQMPBpWGvZjMvRKNtojl96H/9K7A
3jcDwM+WhGhmZuYJmGaWgHKAKVblAtwQhWRFBTg8kKS4U890dTlYYfatwbALcInIpAMZoO0MB9jQ3d3/CeaVFG
6opEL9ERzqrmz6GDywP09gMrh7BvxTMCfaROcvMElygZM2eQDnZyP/AQ4AkBe4urtvAIO7uxvgEzGXiB6RDTW7
u7so4iWYCtQ9TNFlXvCopVNtdDnbvdX6X3BwIcWL7B4j5THifV8Gd/eJGMixPouPd84K3/dEfc5zv1yYyac3IV
uZtvfPqi9DYJrPLQNESAAAAABJRU5ErkJggg==
CukuppanjangmemangkalodijadikankeformatDataURI.Cobakopicontohdatauridiatasdanpastekebrowserurldanjanganlupatekanenter.
ToDataURI
78
PenggunaanUntukkodesumberselengkapnyabisadilihatdiGithubpadabranchtodatauri-mysqlatauketikperintahberikutpadacommandline.
$gitclone-btodatauri-mysqlhttps://github.com/junwatu/todatauritodatauri-mysql
$cdtodatauri-mysql
$npminstall
Adatigapenggunaanaplikasiiniyaitu
DownloadPNG&SimpanKeMySQL
$node./tdi.js<url_image_png_dari_internet>
Aplikasiiniakanmendownloadfileimagepngdariinternetdanmendukungprotokolhttpataupunhttps.
Demo
$node./tdi.js
JikadijalankantanpaargumenmakahasilnyaadalahkeluarandemoyangtidaklainadalahcontohformatDataURI.
TampilkanDataMySQL
$node./tdi.jsshow
JikaadaargumenshowmakadatadalamMySQLakanditampilkansemua.Hatihatijikaandabanyakmengkonversibanyakdatagambarpng.
Penggunaan
79
KonverterPNGKeDataURIMarikitalihatisidarifiletodatauri.js.Padadasarnyafileinimerupakanpustakasederhanayangakanmendownloadimageberformat.pngdiinternetdankemudianmengubahnyamenjadiformatDataURI.
Jadiandabisamenggunakanpustakainisepertihalnyamodulnpmdenganbantuanrequire.
/**
*todatauri.js
*DownloadimageandconvertittoDataURI
*
*WTFPL
*(c)2015,EquanPr.
*/
varfs=require('fs');
varhttp=require('http');
varhttps=require('https');
varurl=require('url');
functionUtil(){
vardefaultImage='https://upload.wikimedia.org/wikipedia/commons/thumb/d/d9/Node
.js_logo.svg/320px-Node.js_logo.svg.png';
varimageDest='download.png';
varfile;
return{
toDataURI:function(urlArg,cb){
varimageURL;
urlArg?imageURL=urlArg:imageURL=defaultImage;
if(url.parse(imageURL).protocol==='https:'){
Util().httpsGetImage(imageURL,function(err,data){
err?cb(err,null):cb(null,data);
});
}else{
Util().httpGetImage(imageURL,function(err,data){
err?cb(err,null):cb(null,data);
});
}
},
httpGetImage:function(url,cb){
file=fs.createWriteStream(imageDest);
http.get(url,function(response){
response.pipe(file);
todatauri.js
81
console.log('Downloadnode.jsdefaultImagefrom',defaultImage);
console.log('\n');
file.on('finish',function(){
file.close();
Util().imageToDataUri(imageDest,function(err,data){
err?cb(err,null):cb(null,data);
});
});
})
},
httpsGetImage:function(url,cb){
file=fs.createWriteStream(imageDest);
https.get(url,function(response){
response.pipe(file);
console.log('Downloadnode.jsdefaultImagefrom',defaultImage);
console.log('\n');
file.on('finish',function(){
file.close();
Util().imageToDataUri(imageDest,function(err,data){
err?cb(err,null):cb(null,data);
});
});
})
},
imageToDataUri:function(imageName,cb){
//TODO:lookupmimetypehere
varmime='image/png';
varencoding='base64';
varuri='data:'+mime+';'+encoding+',';
fs.readFile(imageName,function(err,buf){
if(err)returncb(err,null);
cb(null,uri+buf.toString(encoding));
})
}
}
}
module.exports=Util();
Fungsiutamapadafiletodatauri.jsyaitufungsiimageToDataUri()danjikadilihatisinyamakasebenarnyasangatsederhanauntukmengubahgambarpngkeencodingbase64yangakandigunakandiDataURI.
todatauri.js
82
buf.toString(encoding))
fs.readFile(filename[,options],callback)merupakanfungsiuntukmembacafilesecaraasinkrondanjikaencodingtidakdiberikanmakahasilpembacaanfileakanmengembalikandataberupabuffer.Sehinggauntukmengubahdatabufferinikebase64cukupdenganmemakaimetode.toString(encoding).
todatauri.js
83
KoneksiMySQLUntukkoneksikedatabaseMySQLcukupmudahsepertiyangtelahdibahaspadababsebelumnyatentangNodedanDatabaseMySQL.
/**
*todatauri.jsdenganMysql
*
*
*WTFPL
*EquanPr.
*2015
*/
varUtil=require('./todatauri.js');
varmysql=require('mysql');
varconnection=mysql.createConnection({
host:'localhost',
user:'root',
password:''
});
connection.connect(function(err){
if(err){
console.log(err);
}else{
console.log('KoneksiMySQLdenganid'+connection.threadId);
}
});
varcreate_database='CREATEDATABASEIFNOTEXISTSdata_uri';
varcreate_table="CREATETABLEIFNOTEXISTSdata_uri.images(idINTAUTO_INCREMENT
PRIMARYKEY,dataTEXT)";
connection.query(create_database,function(err,res){
if(err){
console.log(err);
}else{
console.log('Createdatabasedata_uri[ok]');
connection.query(create_table,function(err,result){
if(err){
console.error(err);
}else{
console.log('Createtableimages[ok]');
main(process);
}
})
}
KoneksiMySQL
84
});
functioninsertData(data,connection){
connection.query('INSERTINTOdata_uri.imagesSET?',{data:data},function(er
r,res){
if(err){
console.log(err);
}else{
console.log(res);
closeConnection();
}
})
};
functionshowData(connection){
connection.query('SELECT*FROMdata_uri.images',function(err,result){
if(err){
console.log(err);
}else{
console.log('\n\nMySQLDatabase\n============================\n');
result.forEach(function(element,index){
console.log('id\u2192',element.id);
console.log('image\u2192',element.data);
});
closeConnection();
}
})
}
functionmain(process){
if(process.argv[2]){
if(process.argv[2].toLowerCase().trim()=='show'){
showData(connection);
}else{
Util.toDataURI(process.argv[2],function(err,data){
if(!err){
insertData(data,connection);
}
})
}
}else{
Util.toDataURI(null,function(err,data){
if(!err){
console.log(data);
closeConnection();
}
});
}
}
functioncloseConnection(){
KoneksiMySQL
85
connection.end(function(err){
if(err){
console.log(err);
}
});
}
ParsingargumendilakukanolehprocessyangmerupakanobjectglobaldiNode.js.PerludiingatbahwaJavaScriptmemulaiarraydenganindex0sehinggaargumenyangdiperlukanberadapadaindex2
process.argv[2]
JikaandaberadapadaplatformUNIXatauGNULINUXscriptdiatasbisadirubahuntukselfexecutabledenganmenambahkanscriptberikutpadaline1difiletdi.js
#!/usr/bin/envnode
Kemudianuntukmenjalankannyacukupmudahsepertiberikut
$./tdi.js
Scripttdi.jssebenarnyacukupsederhanadancukupuntukmelakukantugasyangdiinginkan.Mungkinkelihatanagakrumitkarenabanyakcallbackdisanasinitetapikalauandasudahterbiasamemprogramsecaraasinkronpastimudahsekaliuntukmelihatkodediatas.
PenulissarankanuntukkedepannyajikadiinginkanpenulisantanpacallbackbisadipelajaritentangPromisesJavaScriptES6.
KoneksiMySQL
86
PersonRESTAPIAplikasiinimerupakancontohsederhanalayananservermelaluiREST(RepresentationalStateTransfer)yaitumekanismeuntukkomunikasidenganservermelaluiprotokolHTTPyangmudahuntukdigunakandaripadamemakaimekanismeprotokollamasepetiCORBA,SOAPataupunRPC.
AplikasiRESTmemakaimetodeHTTPsepertiPOST,PUT,GETdanDELETEuntukmenambah,mengubah,mengambilataupunmenghapusresourceyangadapadaserver.SehinggadalampengembanganaplikasikhususnyadenganmemakaiNode.js,mekanismeRESTsangatmudahuntukdigunakan.
SusunanAPIBerikutsusunanAPIyangakandigunakandalamcontohaplikasiini.ContohAPIinimungkintidakmengikutibestpracticetapipenulisrasasudahcukupuntukmenggambarkanbagaimanamenyusunaplikasiRESTsecarasederhana.
PersonRESTAPI
87
CaraKerjaCarakerjadariaplikasiPersonRESTinicukupmudah.HanyasajauntukantarmukadenganpenggunatidakmelaluiantarmukawebsepertihalnyakitamengakseshalamanFacebookmisalnya,karenasecaraumumaplikasiRESTfungsinyalebihkememberikanlayanandatamentahsehinggadeveloperbertanggungjawabpenuhuntukapadata-datatersebutdigunakan,apakahakanditampilkankebrowserwebataudigunakanpadaaplikasimobileandroidatauakandigunakanuntukmengaktifkandeviceelektroniksepertiArduino,RaspberryPidll.
UntukaplikasiPersonRESTini,datadisimpandidatabaseMongoDBmelaluioperasiCRUD(Create,Read,Update,Delete)yangdapatdiaksesmelaluirequestAPIyangtelahdisebutkansebelumnya.
DiagramkerjaaplikasiPersonRESTdigambarkanpadadiagramdibawahini
PengetesanoperasiCRUDuntukaplikasibisadenganmenggunakanbantuanalatCommandLineInterfaceseperticURLatauHTTPieataupuntoolyanglebihramahsepertiPostmandanbisajugaandamembangunantarmukawebdenganmemakaiAPIyangdisediakanolehserverPersonini.ContohpengetesanuntukaplikasiPersonRESTinibisalihatpadasub-babPengetesan.
CaraKerja
88
ServerKodesumberdariaplikasiinidapatdidownloaddilinkberikut
https://github.com/junwatu/rest-node-mongoose-mongodb
InstalasiClonekodesumbermelaluigitdaninstaldepedensipaketmelaluinpm
$gitclonehttps://github.com/junwatu/rest-node-mongoose-mongodb.git
$cdrest-node-mongoose-mongodb
$npminstall
PastikandatabaseMongoDBsudahberjalanpadasistemandajikamenggunakanservicesystemdpadalinuxandabisamenjalankannyadenganperintahberikut
$sudoservicemongodstart
KodeUntuklingkunganproduksiadabaiknyauntukmemecahfilekodekebagianyanglebihkecilsupayalebihmudahdalamhalmaintenance.Untukkemudahandankesederhanaanaplikasiinimakakodeutamaditulisdalamsatufile.
app.js
/*
*KoneksiNodejsdenganMongoDBmenggunakanMongoose
*
*AuthorByEquanPr.
*http://equan.me
*
*License:Whateveryouwant!:D
*/
varexpress=require("express"),
app=express(),
mongoose=require('mongoose'),
Server
89
path=require('path'),
engines=require('consolidate');
app.configure(function(){
app.use(express.logger());
app.use(function(req,res,next){
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Methods','GET,PUT,POST,DELETE');
res.header('Access-Control-Allow-Headers','Content-Type')
if('OPTIONS'==req.method){
res.send(200);
}
else{
next();
}
})
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.static(__dirname+'/public'));
app.engine('html',engines.handlebars);
app.set('views',__dirname+'/views');
app.set('viewengine','html');
app.set('PORT',process.env.PORT||5000);
app.set('MONGODB_URI',process.env.MONGOLAB_URI||
process.env.MONGOHQ_URL||'mongodb://localhost/persons');
});
/**
*MongoDBconnection
*/
vardb=mongoose.createConnection(app.get('MONGODB_URI'));
db.on('connected',function(){
console.log('ConnectedtoMongoDB.');
});
db.on('error',function(err){
console.error.bind(console,'ConnectiontoMongoDBerror!.');
});
db.on('close',function(){
console.log('ConnectiontoMongoDBclosed.');
});
//Schema
varPersonsSchema=newmongoose.Schema({
Server
90
name:'string',
username:'string',
website:'string',
createdAt:'date',
updatedAt:'date'
}),
Persons=db.model('Persons',PersonsSchema);
//Routes
app.get("/",function(req,res){
res.render('index',{
data:'SillyRESTfulsampleappbuiltwithNode.js,Express,MongooseandMong
oDB.'+
'Maybeit\'susefulforbeginners;)'
});
});
//GET/persons
app.get("/persons",function(req,res){
//FindAll
Persons.find(function(err,persons){
if(err)res.json({error:err})
if(persons)
res.json({persons:persons});
})
});
//POST/persons
app.post("/persons",function(req,res){
/**
*Getdatafrompost
*@type{Persons}
*/
varperson=newPersons({
name:req.body.name,
username:req.body.username,
website:req.body.website,
createdAt:newDate(),
updatedAt:newDate()
});
person.save(function(err,person){
if(err){
res.send({error:err});
}else{
console.log('Savedata:'+person);
res.json({message:'saveok'});
}
})
});
Server
91
//GET/persons/:username
app.get('/persons/:username',function(req,res){
varparam_username=req.params.username;
Persons.find({username:param_username},function(err,person){
if(err){
res.json({
data:"Errorfindingperson."
});
}else{
res.json({
person:person
});
}
})
});
//PUT/persons/:username
app.put('/persons/:username',function(req,res){
varquery={username:req.params.username},
data_update={
name:req.body.name,
username:req.params.username,
website:req.body.website,
updatedAt:newDate()
}
Persons.update(query,data_update,{multi:false},function(err,numberAffected,ra
wResponse){
if(err){
res.json({
error:err
})
}else{
res.json({
numberAffected:numberAffected,
rawResponse:rawResponse
});
}
});
});
//DELETE/persons/:username
app.delete('/persons/:username',function(req,res){
varparam_username_del=req.params.username;
Persons.remove({username:param_username_del},function(err){
if(err){res.json({
error:err
})
}else{
res.json({message:"deleteok"});
Server
92
PengetesanUntukmenggunakanataupengetesanAPIinicaratermudahadalahdenganmemakaiPostmanataujikaandasudahterbiasamemakaitoolterminalseperticURLatauHttpiesilahkansaja.
Demoaplikasiberadapadalinkberikut,
persons-api.herokuapp.com
POST/personsUntukmembuatdataPersonbarumelaluiapi/personscukupdenganmemakairequestPOST.
GET/persons
Pengetesan
94
MengambildatadenganmengaksesAPI/personsyangakanmengembalikansemuadatayangtelahtersimpansebelumnya.
PUT/persons/:usernameUpdatedatabisadilakukandenganmudahdenganmemakaiPUT.
Pengetesan
95
DELETE/persons/:usernameOperasipenghapusandatahanyabisadilakukansatupersatumelaluikey:username.
Pengetesan
96
ImageUploader
Aplikasiinisangatsederhana,carakerjanyayaitugambardiuploadkeserverdankemudianditampilkankembalikebrowser.
ServerPadasisiserveraplikasiinimemakaiframeworkExpressJSuntukmenanganirequestHTTPdanpaketformidableuntukmenanganifileyangdiupload.
Catatan:AplikasiinimemakaisedikitfiturES6sepertilet,const,arrowfunctionsehinggaandaperlumenginstallsetidaknyaNode.jsv4.2.1LTS
ImageUploader
98
server.post('/upload',(req,res)=>{
letform=newformidable.IncomingForm()
form.uploadDir=path.join(__dirname,'uploads')
form.hash=true
form.multiples=false
form.keepExtensions=true
form.parse(req,(err,fields,files)=>{
if(!err){
console.log(files.file.name)
console.log(files.file.path)
console.log(files.file.type)
}
res.end()
})
})
Kodediatasakanmenanganifileyangakandiuploaddanmenyimpanhasiluploadpadadirektoriuploads.Formidabledapatdenganmudahdikonfigurasi,lihatGithubFormidable.
UploaderPadasisiklienuploderdibangundenganmemakaipustakaDropzoneJSyangmendukungdragndropdanpreviewthumbnail.Pustakainisangatmudahuntukdigunakandandikustomisasi
Dropzone.options.mydropzone={
init:function(){
this.on("complete",function(file){
updateImage()
})
},
maxFileSize:2,
acceptedFiles:'image/*'
}
Konfigurasidiatasmengakibatkanuploaderhanyamenerimafilebertipegambardanukuranfiletidaklebihdari2MBdanyangperludicatatyaituketikafileselesaidiuploadyaitudenganmendengarkaneventcompletemakalistviewgambaryangdibuatdenganKendoUIharusdiupdatedenganmemanggilmetodeupdateImage().
ImageList
ImageUploader
99
Kendoakanmengambildatadariserverkemudiansecaraotomatisakanmengupdate#listViewsesuaidenganbanyaknyagambaryangtelahterupload.
varupdateImage=function(){
vardataSource=newkendo.data.DataSource({
transport:{
read:{
url:document.location.href+'service/images',
dataType:'json'
}
},
pageSize:21
})
$('#pager').kendoPager({
dataSource:dataSource
})
$('#listView').kendoListView({
dataSource:dataSource,
template:kendo.template($('#template').html())
})
}
KomponenKendoUIyangdipakaiadalahListViewdanframeworkUIinisepertiframeworkkebanyakanlainnyajugamemakaitemplateuntukmenghasilkanUIsecaradinamik.
<divclass="demo-sectionk-contentwide">
<divid="listView"></div>
<divid="pager"class="k-pager-wrap"></div>
</div>
<scripttype="text/x-kendo-template"id="template">
<divclass="product">
<imgsrc="/#=ImageName#"/>
<h3>#:ImageId#</h3>
</div>
</script>
DatayangakandiambildariserveryaitudatagambarharusmempunyaifieldImageNamedanImageId.
KomponenyangdisediakanolehKendocukuplengkapdanjikaandatertarikdenganKendoUIlebihlanjutsilahkanberkunjungkewebsiteresmiTelerik.
UntukmengambildaftargambaryangtelahdiuploadklienakanmengaksesURLberikut
ImageUploader
100
http://localhost:5005/service/images
Serverhanyaakanmemfilterfiledengantipejpgdanpngpadafolderuploads.Filterdilakukandenganmengecektipefilemelaluipaketmimetepatnyamelaluimetodemime.lookup(image).
server.get('/service/images',(req,res)=>{
letimages=[]
fs.readdir(upload_dir,(err,files)=>{
if(!err){
for(letimageIndex=0;imageIndex<files.length;imageIndex++){
letftype=mime.lookup(path.join(upload_dir,files[imageIndex]))
if(filetypes.indexOf(ftype)!==-1){
letdata={}
data.ImageId=imageIndex
data.ImageName=files[imageIndex]
images.push(data)
}
}
res.json(images)
}else{
res.end()
}
})
})
DatayangdikembalikankeklienadalahdataJSONdenganformatsepertiberikut
[{
ImageId:1,
ImageName:'file.jpg'
}]
KodesumberdariaplikasiinibisaandadapatkanpadarepoGithubImageUploader.
ImageUploader
101
ECMAScript2015atauES6MeskipunECMAScript2015atauyanglebihdikenalES6sudahdiresmikantetapiimplementasidibrowserdanplatformNode.jsmasihterjadisecaragradual.PadasaatbukuiniditulispadaplatformNode.js4.x(LTS)dan5.xsudahbanyakfitur-fiturES6yangbuilt-indanuntukfituryangbelumdidukungandabisamemakaitoolyangbernamaBabel.
UntukmempelajariES6banyaksekaliresourceonlineyangmenyediakanjadisilahkanandabereksplorasidanmencobakonsep-konsepbaruyangditawarkanolehJavaScript.AndabisamemulaidaribukuonlinegratistentangES6
ExploringJSES6
PadadasarnyaBabelberfungsiuntukmengkompilasiES6(atauES7,8)menjadiES5sehinggabisadijalankanpadabrowseratauplatformNode.jsyangbelummendukungES6.SalahsatupertanyaanterbesarkalauandamemakaiBabeladalahbagaimanamengkompilasihanyabeberapafiturES6sajajikalaubrowserataupunNode.jsyangakankitapakaisecaranativesudahmendukungsebagianataubeberapafiturES6?
BabelonTheFly
SejakdireleaseBabel6,toolinimendukungkompilasiES6berdasarkanpluginartinyaandabisamemilihfiturmanayangakandikompilasikeES5jikamisalnyapadaplatformNode.jssudahmendukungbanyakfiturES6.
Kalauandapernahmemakaibabel-nodemakesekarangdigantidenganpaketbabel-cli
$npminstall-gbabel-cli
Apakegunaannya?babel-clisangatbergunauntukmengkompilasiES6secaraontheflymisalnyabegini
lib/module.js
'usestrict'
exportfunctiontest(){
console.log('test')
}
main.js
MemakaiES6
102
'usestrict'
import{test}from'./lib/module'
test()
Makauntukmengeksekusifilemain.jsbisamelaluibabel-node
$babel-nodemain.js
JikaandamemakaiprojectdenganES6selainbabel-climakapaketberikutjugaperludiinstall
$npminstall--save-devbabelbabel-corebabel-loader
danjugasettingfile.babelrc(meskipunsebenarnyaadabeberapaalternatiflaindimanaharusmenuliskansettingbabeltapicarainilebihUNIX,tergantungseleramasingmasing)
.babelrc
{
"plugins":["transform-es2015-modules-commonjs"]
}
Bisaandalihatbahwapluginsyangakankitagunakanadalahtransform-es2015-modules-commonjsjadiharusdiinstalljuga
$npminstall--save-devbabel-plugin-transform-es2015-modules-commonjs
Lalubagaimanakalaukitamenginginkansemuapluginkitapakai?jawabannyaadalahdenganmemakaipresets
$npminstall--save-devbabel-preset-es2015
dan.babelrcperluandarubahmenjadisepertidibawahini
{
"presets":["es2015"]
}
CatatanPenjelasandiatasberlakuuntukJavaScriptyangdigunakanpadasisiserveruntukclientatauJavaScriptyangberjalanpadabrowserandabisamemakaiwebpackbersamadenganbabel.
MemakaiES6
103
TentangPengarangEquanPr.adalahdeveloperNodeJSdanpeminumkopikelasberat.SelalusibukdenganyangberbauJavaScriptketikadidepankomputer,penggilafilm&musikmetaldankadang-kadangnge-twitdi@junwatuataunge-Github.
TentangPengarang
105
top related