Upload
phamthuy
View
266
Download
0
Embed Size (px)
Citation preview
0
1
1.1
1.2
2
2.1
2.2
3
3.1
4
5
5.1
5.2
6
6.1
6.2
7
7.1
7.1.1
7.1.2
7.2
8
8.1
8.1.1
8.1.2
8.1.2.1
8.2
8.2.1
8.3
8.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
AplikasiWebNode.js
2
8.3.2
9
9.1
9.2
10
10.1
10.2
10.3
11
11.1
11.2
11.3
12
13
14
Mongoose
Testing
REST
Automasi
ToDataURI
Penggunaan
todatauri.js
KoneksiMySQL
PersonRESTAPI
CaraKerja
Server
Pengetesan
ImageUploader
MemakaiES6
TentangPengarang
AplikasiWebNode.js
3
AplikasiWebNode.jsNote:ThisbookiswritteninBahasaIndonesiaandthemainreasonforthatisbecausemostofNode.jsbeginnersinmycountryIndonesiaishavingdifficultiestofindNode.jsresourceswritteninmynativelanguage.
BukuinicocokbagisiapasajayanginginmulaibelajarpemrogramandiplatformNode.jskhususnyauntukmembangunaplikasiweb.SyaratyangdibutuhkanadalahpembacasetidaknyapernahatausudahbisamemakaibahasapemrogramanJavaScript.
Ebookinibisaandaaksesdiduatempatyaitu:
GithubIDJS(versionline).Gitbook(versionline,PDF,Epub&Mobi).
FeedbackUntukpertanyaan,kesalahanketikataupermintaanbisamenghubungipenulismelaluiemailequan.p[at]gmail.meataumelaluiGithubissue.
LisensiAplikasiWebNode.jsolehEquanPr.dikerjakandibawahlisensiCreativeCommonsAttribution-NonCommercial4.0InternationalLicense.
AplikasiWebNode.js
4Introduction
Node.jsJavascriptmerupakanbahasapemrogramanyanglengkaphanyasajaselamainidipakaisebagaibahasauntukpengembanganaplikasiwebyangberjalanpadasisiclientataubrowsersaja.TetapisejakditemukannyaNode.jsolehRyanDhalpadatahun2009,JavascriptbisadigunakansebagaibahasapemrogramandisisiserversekelasdenganPHP,ASP,C#,RubydlldengankatalainNode.jsmenyediakanplatformuntukmembuataplikasiJavascriptdapatdijalankandisisiserver.
UntukmengeksekusiJavascriptsebagaibahasaserverdiperlukanengineyangcepatdanmempunyaiperformansiyangbagus.EngineJavascriptdariGooglebernamaV8yangdipakaiolehNode.jsyangmerupakanengineyangsamayangdipakaidibrowserGoogleChrome.
AplikasiWebNode.js
5Node.js
JavaScriptDiServerTakterelakkanbahwaJavascriptmerupakanbahasapemrogramanyangpalingpopuler.JikaandasebagaideveloperpernahmengembangkanaplikasiwebmakapenggunaanJavascriptpastitidakterhindarkan.
SekarangdenganberjalannyaJavascriptdiserverlaluapakeuntunganyangandaperolehdenganmempelajariNode.js,kuranglebihsepertiini:
Pengembanghanyamemakaisatubahasauntukmengembangkanaplikasilengkapclient&serversehinggamengurangiLearningCurveuntukmempelajaribahasaserveryanglain.
Sharingkodeantaraclientdanserveratauistilahnyacodereuse.
JavascriptsecaranativemendukungJSONyangmerupakanstandartransferdatayangbanyakdipakaisaatinisehinggauntukmengkonsumsidata-datadaripihakketigapemrosesandiNode.jsakansangatmudahsekali.
DatabaseNoSQLsepertiMongoDBdanCouchDBmendukunglangsungJavascriptsehinggainterfacingdengandatabaseiniakanjauhlebihmudah.
Node.jsmemakaiV8yangselalumengikutiperkembanganstandarECMAScript,jaditidakperluadakekhawatiranbahwabrowsertidakakanmendukungfitur-fiturdiNode.js.
AplikasiWebNode.js
6JavaScriptDiServer
Node.jsInActionSupayaandalebihtertarikdalambelajarNode.jsberikutbeberapawebsiteterkenalyangsudahmemakaiNode.js
www.myspace.com
www.yummly.com
www.shutterstock.com
AplikasiWebNode.js
7Node.jsInAction
www.learnboost.com
ApakahmasihraguuntukmemakaiNode.js?...KalaumasihpenasaranapayangmembuatNode.jsberbedadaribackendpadaumumnya,silahkandilanjutkanmembaca:smile:
AplikasiWebNode.js
9Node.jsInAction
AsinkronI/O&EventTidaksepertikebanyakanbahasabackendlainnyaoperasifungsidijavascriptlebihbersifatasinkrondanbanyakmenggunakaneventdemikianjugadenganNode.js.SebelumpenjelasanlebihlanjutmarikitalihatterlebihdahulutentangmetodesinkronsepertiyangdipakaipadaPHPdenganwebserverApache.
AplikasiWebNode.js
10AsinkronI/O&Event
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
AplikasiWebNode.js
11PHP&ServerHTTPApache
BisadilihatbahwaNginxbisamenanganirequestyangjauhlebihbanyakdaripadawebserverApachepadajumlahkoneksibersamayangsemakinnaik.
AplikasiWebNode.js
12PHP&ServerHTTPApache
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:
AplikasiWebNode.js
13Javascript&Node.js
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
AplikasiWebNode.js
15ServerHTTPDasar
<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.
AplikasiWebNode.js
16ServerHTTPDasar
MenjalankanServerUntukmenjalankanserverNode.jsketikperintahberikutditerminal
$nodeserver-http.js
Port3400:Node.jsServer...
Bukabrowser(chrome)danbukaurlhttp://localhost:3400kemudianketikCTRL+SHIFT+IuntukmembukaChromeDevTool,dengantoolinibisadilihatresponheaderdariHTTPdimanabeberapafieldnyatelahdisetsebelumnya(lingkaranmerahpadascreenshotdibawahini).
AplikasiWebNode.js
17MenjalankanServer
ServerFileStatisAplikasiwebmemerlukanfile-filestatissepertiCSS,fontdangambarataufile-filelibraryJavaScriptagaraplikasiwebbekerjasebagaimanamestinya.File-fileinisengajadipisahkanagarterstrukturdansecarabestpracticesfile-fileinimemangharusdipisahkan.LalubagaimanacaranyaNode.jsbisamenyediakanfile-fileini?...okmarikitabuatserverNode.jsyangfungsinyauntukmenyediakanfilestatis.
AgarserverNode.jsbisamengirimkanfilestatiskeklienmakaserverperlumengetahuipathatautempatdimanafiletersebutberada.
Node.jsbisamengirimkanfiletersebutsecarastreamingmelaluifungsifs.createReadStream().SebelumdijelaskanlebihlanjutmungkinbisadilihatataudicobasajaserverfileNode.jsdibawahini
server-file.js
AplikasiWebNode.js
18ServerFileStatis
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)
AplikasiWebNode.js
19ServerFileStatis
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
AplikasiWebNode.js
20ServerFileStatis
PemrosesanDataFormHTMLAplikasiwebmemperolehdatadaripenggunaumumnyamelaluipengisianformHTML.ContohnyasepertiketikaregistrasidimediasosialatauaktifitasupdatestatusdiFacebookmisalnyapastiakanmengisitextfielddankemudianmenekantombolsubmitataupunenteragardatabisaterkirimdandiprosesolehserver.
Datayangdikirimolehformbiasanyasalahsatudariduatipemimeberikut
application/x-www-form-urlencodedmultipart/form-data
Node.jssendirihanyamenyediakanparsingdatamelaluibodydarirequestsedangkanuntukvalidasiataupemrosesandataakandiserahkankepadakomunitas.
AplikasiWebNode.js
21PemrosesanDataFormHTML
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;
AplikasiWebNode.js
22URLEncode
});
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
AplikasiWebNode.js
23URLEncode
modulequerystringdariNode.jsberfungsiuntukmengubahurlencodedstringmenjadiobjekJavaScript.Contohnya
querystring.parse('nama=lanadelrey&job=singer&album=borntodie&ultraviolence');
//returns
{nama:'lanadelrey',job:'singer',album:['borntodie','ultraviolence']}
AplikasiWebNode.js
25URLEncode
MultipartDataParsingdataformdanfileyangdiuploadkeserverNode.jsadalahpekerjaanyangcukupsusahkalodikerjakansecaramanualataudariscratchkarenadisampingharusparsingdatabinaryyangberupafilejugaharusparsingdataform.
Protokoluntukmultipart/form-datadidefinisikansecaralengkapdiRFC2388.
AplikasiWebNode.js
26MultipartData
ModuleNpmnicepeoplematter
npmmerupakanpackagemanageruntukNode.jsdanuntuknamanpmbukanlahsuatusingkatan.Hanyadalamwaktu2tahunsejakdireleasenyaNode.jskepublikjumlahmodulmelesatjauhbahkanhampirmenyamaimoduljavaataupunrubygems.
Grafikdiatasdidapatdarihttp://modulecounts.com.
BanyaknyapushmodulekerepositorinpmdapatdiartikanadanyakepercayaanpublikterhadapplatforminidanuntukkedepannyaNode.jsakanmenjadiplatformyangprospektifuntukberinvestasi.
AplikasiWebNode.js
27Modulenpm
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.
AplikasiWebNode.js
28Konsep
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.
AplikasiWebNode.js
29Paketnpm
Secaragarisbesarprosespembuatanpaketnpmmenurutalurdiatasakandijelaskansebagaiberikut
Registrasi
Sebelumpublishkeregistrynpmjs.orgkitaharusregistrasidulumelaluiperintahberikut
AplikasiWebNode.js
30Paketnpm
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",
AplikasiWebNode.js
31Paketnpm
"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.
AplikasiWebNode.js
32Paketnpm
ExpressJSUntukmemudahkanpembuatanaplikasiwebandabisamenggunakanframeworkExpressJSdaripadaharusmenggunakanmodulehttpbawaanNode.js.Frameworkinimenawarkanbeberapafitursepertirouting,renderingviewdanmendukungmiddlewaredengankatalainandaakanbanyakmenghematwaktudalampengembanganaplikasiNode.js.
ExpressJSmerupakanframeworkminimalyangsangatfleksibel.AndabisamembuatwebserverHTML,serverfilestatik,aplikasichat,searchengine,sosialmedia,layananwebdenganaksesmelaluiRESTAPIatauaplikasihybridyaituselainpenggunamempunyaiaksesmelaluiRESTAPIjugamempunyaiakseskeHTMLpage.
AplikasiWebNode.js
33ExpressJS
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
AplikasiWebNode.js
34ServerFile
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.
AplikasiWebNode.js
35ServerFile
MiddlewareFungsionalitasyangdiberikanolehExpressJSdibantuolehyangnamanyamiddlewareyaitufungsiasinkronyangbisamengubahrequestdanrespondiserver.
Padakodediatascontohmiddlewareyaitumodulmorgan.Carapemakaianmiddlewareyaitumelaluiapp.use().
Modulemorganmerupakanmoduluntukloggeryangberfungsiuntukpencatatantiaprequestkeserver.Pencatataniniatauistilahnyaloggingakanditunjukkandiconsoleterminal.
Untukmenginstallmoduliniketikperintahberikut
$npminstallmorgan--save
Middlewaremiddlewareinibisaandalihatdilinkberikut
https://github.com/senchalabs/connect#middleware
AplikasiWebNode.js
36Middleware
AksesServerUntukmenjalankanserverfilestatikini
$nodeapp.js
Andabisameletakkanfileapasajapadadirektori'publik'.Untukmengaksesserveriniketikalamatberikutpadabrowser
http://localhost:4000
dansecaradefaultakanmenampilkanfileindex.htmldibrowser.
UntukmengaksesfileyanglainformatURLadalah
http://localhost:4000/[nama-file]
misalnyauntukmengaksesfileimg.jpg
AplikasiWebNode.js
37AksesServer
ServerRESTFrameworkExpressJSsangatbanyakdigunakansebagaiaplikasiRESTful.Bagiandayangbelumtahu,RESTatauRepresentationalStateTransferadalaharsitekturyangdigunakandalamdesainaplikasinetwork.IdenyayaitudaripadamemakaitekniksepertiCORBA,SOAPatauRPCuntukmembuatWebServicelebihbaikjikamemakaiprotokolHTTPyanglebihmudah.
AplikasiRESTfulmemakairequestHTTPuntukoperasiCreate,Read,UpdatedanDeletedata.RESTitusendiribukanlahsuatustandardjaditidakadayangnamanyaspecdariW3C.Sehinggasangatmudahbagibahasapemrogramanuntukmenggunakanarsitekturini.KeuntunganlainnyayaitudenganarsitekturinibisadibangunberbagaimacamteknologikliensepertiwebataumobileataupundekstopuntukmengaksesaplikasiRESTfultersebut.
UntukcontohaplikasiRESTfulmemakaiExpressJSakandiberikanpadaBabPersonRESTAPI.
AplikasiWebNode.js
38ServerREST
DatabaseBerkembangpesatnyakomunitasNode.jsmenyebabkandukunganpustakayangsemakincepatjuga.DenganwaktuyangrelatifcepatplatforminisekarangmendukungbanyaktipedatabasesepertiSQLite,MySQL,MongoDB,Redis,CouchDBdll.Dalambukuinihanyaakandibahasa3databasesajayaituSQLite,MySQLdanMongoDB.
AplikasiWebNode.js
39Database
SQLiteMungkindatabaseinisudahtidakasinglagibagidevelopersepertiandakarenamemangbanyakdigunakandalamaplikasiportabledanembeddable.
KekuatanSQLitesecaragarisbesarsebagaiberikut
Serverless
SQLitetidakmemerlukanproseslainuntukberoperasisepertipadadatabaselainyangumumnyasebagaiserver.LibrarySQLiteakanmengaksesfiledatasecaralangsung.
ZeroConfiguration
Karenasifatnyabukanservermakadatabaseinitidakmemerlukansetuptertentu.Untukmembuatdatabasecukupsepertiketikamembuatfilebaru.
Cross-Platfrom
Semuadatatersimpanpadasatusistemfileyangbersifatcrossplatformdantidakmemerlukanadministrasi.
Self-Contained
LibrarySQLitesudahmencakupsemuasistemdatabasesehinggadenganmudahdapatdiintegrasikankeaplikasihost.
SmallRuntimeFootprint
UkurandefaultdariSQLiteinikurangdari1MBdanmembutuhkanhanyabeberapaMegabytememory.
Transactional
OperasitransaksikompatibeldenganACIDsehinggaamankalauharusmengaksesdatadariprosesbanyakthread.
Untukpenjelasanlebihdetil,silahkankunjungiwebsiteresmihttp://sqlite.org
AplikasiWebNode.js
40SQLite
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(idINTEGERPRIMARYKEYAUTOINCREMENT,judulTEXTNOTNULL,releaseTEXTNOTNULL,imdbTEXT,deskripsiTEXT)";
AplikasiWebNode.js
41NodeSqlite3
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],function(err){
if(err){
console.log(err);
}else{
console.log('INSERTDATA');
}
});
//Queryalldata
selectAllData();
//Updatedata
db.run(UPDATE_DATA,{$deskripsi:filmUpdate.deskripsi,$id:filmUpdate.id},function(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");
};
})
});
functionselectAllData(){
db.each(SELECT_DATA,function(err,rows){
if(!err){
console.log(rows);
AplikasiWebNode.js
42NodeSqlite3
}
})
}
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.
AplikasiWebNode.js
43NodeSqlite3
EnkripsiKalauandamemakaiSQLitedanmembutuhkansupayadatabaseiniterenkripsimakaberuntunglahkarenanodesqlite3mendukungpenggunaandatabaseSQLiteyangterenkripsi.
EnkripsiyangdidukungolehSQLiteyaitumelaluiekstensisqlcipher.Sqlciphermerupakanekstensisqliteyangmendukungenkripsi256bitAES.Ekstensiinibisadididownloadmelaluiwebsiteberikut
https://github.com/sqlcipher/sqlcipher
AplikasiWebNode.js
44Enkripsi
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
AplikasiWebNode.js
45Enkripsi
danjikaSQLitememakaienkripsibisadilihatdariscreenshotdibawahinibahwaisidaridatabasemenjadi"meaningless".
AplikasiWebNode.js
46Enkripsi
MySQLKalauandaterbiasadenganbahasapemrogramanPHPmakapastisudahtidakasinglagidengandatabaserelasionalyangpalingbanyakdipakaisaatiniyaituMySQL.
AplikasiWebNode.js
48MySQL
NodeMySQLImplementasidriverdariMySQLuntukplatformNode.jssudahsangatmaturesepertimodulnode-mysqldihttps://github.com/felixge/node-mysql/
InstalasiSepertibiasauntukmenginstallmodulinidansecaraotomatismenyimpannama&versimoduldifilepackage.jsonyaitudenganmemakaiperintahberikut
$npminstall--savemysql
KoneksiSederhanaUntukmembuatkoneksikedatabaseMySQLsalahsatucaranyaadalahdenganmenggunakanmetodeconnection.connect()
AplikasiWebNode.js
49NodeMySQL
//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
AplikasiWebNode.js
50NodeMySQL
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.
AplikasiWebNode.js
51NodeMySQL
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.
AplikasiWebNode.js
52NodeMySQL
MongoDBKalauandasudahterbiasamemakaidatabaserelasionalsepertiMySQLmungkindiperlukansedikitperubahanmindsetuntukmengenaltipedatabaseyangnamanyaNoSQL.Sepertiartidarinamanya,databaseinimerupakandatabaseyangtidakmemakaibahasaSQLquerydatatapibisasecaralangsungmenggunakanbahasapemrogramanclientsebagaicontohadalahMongoDB.
DatabaseNoSQLsepertiMongoDBmenyimpandatasebagaidokumenyangschema-lessyangartinyayaitudatayangdisimpanmempunyaikey-valueyangtidakterikatataubebas.AndabisamembayangkannyasebagaidataJSONyangtersimpandidatabase.
KlienbisaberinteraksilangsungdengandatabaseMongoDBdenganmenggunakanshellJavaScriptmongountukadministrasidanquerydata.Sebagaicontohjikakitainginmembuatsampledatasebanyak100dicollectionsamplemakaperintahdalamshelladalahsepertiberikut,
AplikasiWebNode.js
53MongoDB
$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
AplikasiWebNode.js
54MongoDB
DocumentitusendiriadalahdatayangtersimpandidatabaseNoSQLdandidefinisikanolehyangnamanyaSchema.
Schema
SebelumnyadikatakanbahwaNoSQLmenyimpandatayangschema-less,memangbenartapitetapuntukmenyimpansuatudokumendidatabasebiasanyaaplikasibekerjadenganmodeldatatertentumisalnyauntukdataPersonbisamempunyaikey-valuesepertiberikut
{
nama:"KeboIjo",
email:"[email protected]",
username:"obek_seloso"
}
AplikasiWebNode.js
55MongoDB
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
AplikasiWebNode.js
56NodeMongoDB
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
AplikasiWebNode.js
57NodeMongoDB
/**
*BalajarNode-MongoDB
*
*
*MIT
*EquanPr.2015
*/
varPersonSchema=require('./person.js');
varMongoClient=require('mongodb').MongoClient;
varMONGODB_URL='mongodb://localhost:27017/sample';
varperson=newPersonSchema({
nama:'KeboIjo',
email:'[email protected]',
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")
>
AplikasiWebNode.js
58NodeMongoDB
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:'[email protected]',
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,function(err,result){
if(err){
console.log(err);
}else{
console.log('Datapersonberhasildimodifikasi!');
}
db.close();
})
}
})
});
MetodeupdateOne()mempunyaibeberapaargumensepertiberikut
AplikasiWebNode.js
59NodeMongoDB
updateOne(filter,update,options,callback)
Untukdataupdateandabisamemakaioperatorseperti$setcontohnyasepertiberikutini
db.collection('persons').updateOne({nama:person.nama},{$set:{nama:'Angel'}},function(err,result){
if(err){
console.log(err);
}else{
console.log('Datapersonberhasildimodifikasi!');
}
db.close();
})
daribeberapaoptionsyangterpentingadalahkeyupsertyaituupdateinsertdanjikaoptioninidiberikanmakajikadatayangakandi-updatetidakadamakaMongoDBsecaraotomatisakanmembuatdatayangbaru.UntuklebihjelasnyaandabisamelihatdokumentasidariAPIupdateOne().
QueryQuerydatapadadatabaseMongoDBdapatdenganmudahdilakukandenganmemakaimetodefind(),sebagaicontohuntukmenemukandatapersonpadacollectionpersons
AplikasiWebNode.js
60NodeMongoDB
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.
AplikasiWebNode.js
61NodeMongoDB
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.
AplikasiWebNode.js
62NodeMongoDB
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
AplikasiWebNode.js
63Mongoose
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,'lokasiWisataBatu')
KodediatasmemberiartibahwaaplikasiakanmemakaimodelLokasidenganschematypeyangtelahdidefinisikansebelumnyayaitulokasiWisataKotaBatuSchemadanmodeliniakandisimpanpadakoleksidatadiMongoDBdengannamakoleksiadalahlokasiWisataBatu.
UntukmemakaimodelLokasicaranyaadalahdenganmenciptakaninstancedarimodeltersebut
AplikasiWebNode.js
64Mongoose
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.
AplikasiWebNode.js
65Mongoose
TestingPerangkatlunaktidakadayangsempurnadanpastimempunyaibugs.Salahsatucarauntukmenguranginyaataumencegahnyauntukmunculdikemudianhariadalahdenganjalanmelakukanpengetesan.Pengetesanmemberikankeyakinanpadadeveloperbahwaperangkatlunakbekerjasebagaimanamestinyadanjikaadaperubahanmisalnyapenambahanataupenguranganfiturdipastikanbahwapengetesanakanselaluberhasil.
AdabanyaktipepengetesantetapidalampengembanganaplikasiwebadaduatipepengetesanyangpentinguntukdiketahuiyaituUnitTestingdanAcceptanceTesting.
UnitTestingUnitTestingdilakukanlangsungpadalevelkodeaplikasiyaitupadafungsiataumetodedanadaduametodologiyangseringdigunakanyaituTDDdanBDD.DalamJavaScripttersediabanyakpustakayangdibuatuntukpengetesansepertimoduleassertbawaandariNode.js,Nodeunit,Mocha,Jasminedll.
TestDrivenDevelopment(TDD)
IstilahTDDinimenjadisangatkerenbeberapatahunbelakanganini.KonsepTDDadalahmelakukanpengetesanterlebihdahulubarukemudianmenuliskodedariaplikasi,jadimindsetdaripembuatanperangkatlunakdibalikkalodalampengembanganperangkatlunakyangkonvensionalalurnyayaitumenuliskodeterlebihdahulubarukemudianmenuliskodeuntukpengetesansedangkandalamTestDrivenDevelopmentprosesinidibalik.
Kelemahanpengetesaniniadalahpadaprosesawalbiasanyadibutuhkanwaktuyangrelatiflebihlamauntukmengembangkanaplikasikarenaharusmenuliskodepengetesanterlebihdahulutetapikeuntunganjangkapanjangnyayaituaplikasiyangdihasilkanbiasanyamempunyaibugsyanglebihsedikit.
BehaviorDrivenDevelopment(BDD)
PengetesansecaraBDDmemakaibahasaataumetodepengetesanyanglebihramahyaitudenganmelakukanpengetesandengancaraataualursepertiuserstorysehinggapengetesaninirelatiflebihpopulerkarenasecarabahasamenjembataniataumemungkinkankolaborasiantaradeveloperdanklien.AdabanyakpustakapengetesanyangmemakaiBDDsepertiMocha,Jasmin,Vowsdll.SebagaigambarancontohuntukpustakaMochamisalnya
AplikasiWebNode.js
66Testing
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.
AplikasiWebNode.js
67Testing
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()
})
})
})
})
AplikasiWebNode.js
68REST
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
AplikasiWebNode.js
69REST
Sebenarnyabanyakyangbisadijelaskantentangpengetesandansudahbanyakresourceonlinediluarsanayangmembahastentanginitapiyangperluandaingatadalahpastikanpengetesandimasukkandalamalurkerjadalampengembanganperangkatlunakyangsedangandakerjakan.
AplikasiWebNode.js
70REST
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
AplikasiWebNode.js
71Automasi
language:node_js
node_js:
-"4.1"
-"4.0"
KemudianandaperlumengaturkonfigurasirepodiGithub(TestingLearn).SupayaGithubbisamemakaiservicedariTravismakaandaperlumeengubahkonfigurasirepo(MasukkemenuSettings)
EnableBuild
SupayabuildselaludijalankanolehTravismakaandaharusmeng-ON-kantombolenableditravis-ci.orgpadarepoyangandainginkan.
TestBuild
AplikasiWebNode.js
72Automasi
BuildakandijalankanolehTravissetiapadakodebarudiGithubatauandabisamenggunakantombolTestServicepadaSettings->Webhooks&servicesuntukforcebuild.
Notifikasi
NotifikasiTravisbisadiintegrasikandenganSlack,Email,dllataubiasanyadengangambarstatusdiREADMErepo.UntukkonfigurasigambarstatuskliktombolBuild/PassingdisebelahnamarepodiTravisdancopypastekeREADMErepodiGithub.
SehinggajikaandamembukarepodiGithubmakaakanmunculgambarstatusyangapakahbuildsuksesataudalamstatuserror.
AplikasiWebNode.js
73Automasi
ToDataURIAplikasiiniadalahaplikasiNode.jsCLIyangmengubahgambarpngkeformatdataURIdankemudianmenyimpandatatersebutkedatabaseMySQL.Prosesinibisadigambarkansepertigambaralurdibawahini.
DataURIBagiyangbelumtahuDataURIadalahsalahsatucarauntukmeng-embeddatasecarainlinealih-alihharusmengambildatatersebutdariresourceluar.DatayangakandiubahkeDataURIdisinibisaberupaimage,filecsvdll.Untukaplikasiinihanyadibatasiuntukgambarberformatpng.
FormatDataURIadalahsepertiberikutini
data:[<MIME-type>][;charset=<encoding>][;base64],<data>
Umumnyauntukgambarjenisencodingyangdipakaiadalahbase64.SebagaicontohnyalihatformatgambarpngyangtelahdirubahkeDataURIberikutini
AplikasiWebNode.js
75ToDataURI
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFgAAAAfCAMAAABUFvrSAAAABGdBTUEAANjr9RwUqgAAACBjSFJNAABtmAAAc44AAPXqAACD0AAAfHIAAN7iAAAyWgAAI0zujJoVAAADAFBMVEXW1tYxLS6EgYKtrKy7uro/OzxoZWZMSUrk5OR2c3SfnZ7y8vJaV1iRj5DJyMgjHyD///8RERESEhITExMUFBQVFRUWFhYXFxcYGBgZGRkaGhobGxscHBwdHR0eHh4fHx8gICAhISEiIiIjIyMkJCQlJSUmJiYnJycoKCgpKSkqKiorKyssLCwtLS0uLi4vLy8wMDAxMTEyMjIzMzM0NDQ1NTU2NjY3Nzc4ODg5OTk6Ojo7Ozs8PDw9PT0+Pj4/Pz9AQEBBQUFCQkJDQ0NERERFRUVGRkZHR0dISEhJSUlKSkpLS0tMTExNTU1OTk5PT09QUFBRUVFSUlJTU1NUVFRVVVVWVlZXV1dYWFhZWVlaWlpbW1tcXFxdXV1eXl5fX19gYGBhYWFiYmJjY2NkZGRlZWVmZmZnZ2doaGhpaWlqampra2tsbGxtbW1ubm5vb29wcHBxcXFycnJzc3N0dHR1dXV2dnZ3d3d4eHh5eXl6enp7e3t8fHx9fX1+fn5/f3+AgICBgYGCgoKDg4OEhISFhYWGhoaHh4eIiIiJiYmKioqLi4uMjIyNjY2Ojo6Pj4+QkJCRkZGSkpKTk5OUlJSVlZWWlpaXl5eYmJiZmZmampqbm5ucnJydnZ2enp6fn5+goKChoaGioqKjo6OkpKSlpaWmpqanp6eoqKipqamqqqqrq6usrKytra2urq6vr6+wsLCxsbGysrKzs7O0tLS1tbW2tra3t7e4uLi5ubm6urq7u7u8vLy9vb2+vr6/v7/AwMDBwcHCwsLDw8PExMTFxcXGxsbHx8fIyMjJycnKysrLy8vMzMzNzc3Ozs7Pz8/Q0NDR0dHS0tLT09PU1NTV1dXW1tbX19fY2NjZ2dna2trb29vc3Nzd3d3e3t7f39/g4ODh4eHi4uLj4+Pk5OTl5eXm5ubn5+fo6Ojp6enq6urr6+vs7Ozt7e3u7u7v7+/w8PDx8fHy8vLz8/P09PT19fX29vb39/f4+Pj5+fn6+vr7+/v8/Pz9/f3+/v7///8EKbe0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAB/0lEQVRIx62W2W7sIBBE2Rf3UvX/X5sHYyczyb2eGRnJEjZw6C4KTOD7pQAtXHUKH4AthRabldvBIQZmm7GHm8HcOiVTErabweyF6mSJ82bwNjl2Uexe8IiyVxzlVjDnoYEdU9wEFoxVqdut4FFPU9dbwTmdscf8Cjj/6BXOwUzP85vxWLXZXwGbSRAnGQZdJZBOuqhzBJLBz34jLvL42xi/wB5T69JTS66uJEZPKXpLSaWntBR1LdAj5JjlFbCS2BLpC2yJ1C2qxtx6OzwQm9YVqWway4vgolKmq1dxZJVRcx9issmoa0CJW+hnoF7n5eKFRCqzzhASTbMya5rBWyssTX+69nt1pfR2j93W4KWAIWq6AAc/8nN/45diVxpPIO6btQMPBpWGvZjMvRKNtojl96H/9K7A3jcDwM+WhGhmZuYJmGaWgHKAKVblAtwQhWRFBTg8kKS4U890dTlYYfatwbALcInIpAMZoO0MB9jQ3d3/CeaVFG6opEL9ERzqrmz6GDywP09gMrh7BvxTMCfaROcvMElygZM2eQDnZyP/AQ4AkBe4urtvAIO7uxvgEzGXiB6RDTW7u7so4iWYCtQ9TNFlXvCopVNtdDnbvdX6X3BwIcWL7B4j5THifV8Gd/eJGMixPouPd84K3/dEfc5zv1yYyac3IVuZtvfPqi9DYJrPLQNESAAAAABJRU5ErkJggg==
CukuppanjangmemangkalodijadikankeformatDataURI.Cobakopicontohdatauridiatasdanpastekebrowserurldanjanganlupatekanenter.
AplikasiWebNode.js
76ToDataURI
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.
AplikasiWebNode.js
77Penggunaan
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);
AplikasiWebNode.js
78todatauri.js
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.
AplikasiWebNode.js
79todatauri.js
buf.toString(encoding))
fs.readFile(filename[,options],callback)merupakanfungsiuntukmembacafilesecaraasinkrondanjikaencodingtidakdiberikanmakahasilpembacaanfileakanmengembalikandataberupabuffer.Sehinggauntukmengubahdatabufferinikebase64cukupdenganmemakaimetode.toString(encoding).
AplikasiWebNode.js
80todatauri.js
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_INCREMENTPRIMARYKEY,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);
}
})
}
});
AplikasiWebNode.js
81KoneksiMySQL
functioninsertData(data,connection){
connection.query('INSERTINTOdata_uri.imagesSET?',{data:data},function(err,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(){
connection.end(function(err){
if(err){
AplikasiWebNode.js
82KoneksiMySQL
console.log(err);
}
});
}
ParsingargumendilakukanolehprocessyangmerupakanobjectglobaldiNode.js.PerludiingatbahwaJavaScriptmemulaiarraydenganindex0sehinggaargumenyangdiperlukanberadapadaindex2
process.argv[2]
JikaandaberadapadaplatformUNIXatauGNULINUXscriptdiatasbisadirubahuntukselfexecutabledenganmenambahkanscriptberikutpadaline1difiletdi.js
#!/usr/bin/envnode
Kemudianuntukmenjalankannyacukupmudahsepertiberikut
$./tdi.js
Scripttdi.jssebenarnyacukupsederhanadancukupuntukmelakukantugasyangdiinginkan.Mungkinkelihatanagakrumitkarenabanyakcallbackdisanasinitetapikalauandasudahterbiasamemprogramsecaraasinkronpastimudahsekaliuntukmelihatkodediatas.
PenulissarankanuntukkedepannyajikadiinginkanpenulisantanpacallbackbisadipelajaritentangPromisesJavaScriptES6.
AplikasiWebNode.js
83KoneksiMySQL
PersonRESTAPIAplikasiinimerupakancontohsederhanalayananservermelaluiREST(RepresentationalStateTransfer)yaitumekanismeuntukkomunikasidenganservermelaluiprotokolHTTPyangmudahuntukdigunakandaripadamemakaimekanismeprotokollamasepetiCORBA,SOAPataupunRPC.
AplikasiRESTmemakaimetodeHTTPsepertiPOST,PUT,GETdanDELETEuntukmenambah,mengubah,mengambilataupunmenghapusresourceyangadapadaserver.SehinggadalampengembanganaplikasikhususnyadenganmemakaiNode.js,mekanismeRESTsangatmudahuntukdigunakan.
SusunanAPIBerikutsusunanAPIyangakandigunakandalamcontohaplikasiini.ContohAPIinimungkintidakmengikutibestpracticetapipenulisrasasudahcukupuntukmenggambarkanbagaimanamenyusunaplikasiRESTsecarasederhana.
AplikasiWebNode.js
84PersonRESTAPI
CaraKerjaCarakerjadariaplikasiPersonRESTinicukupmudah.HanyasajauntukantarmukadenganpenggunatidakmelaluiantarmukawebsepertihalnyakitamengakseshalamanFacebookmisalnya,karenasecaraumumaplikasiRESTfungsinyalebihkememberikanlayanandatamentahsehinggadeveloperbertanggungjawabpenuhuntukapadata-datatersebutdigunakan,apakahakanditampilkankebrowserwebataudigunakanpadaaplikasimobileandroidatauakandigunakanuntukmengaktifkandeviceelektroniksepertiArduino,RaspberryPidll.
UntukaplikasiPersonRESTini,datadisimpandidatabaseMongoDBmelaluioperasiCRUD(Create,Read,Update,Delete)yangdapatdiaksesmelaluirequestAPIyangtelahdisebutkansebelumnya.
DiagramkerjaaplikasiPersonRESTdigambarkanpadadiagramdibawahini
PengetesanoperasiCRUDuntukaplikasibisadenganmenggunakanbantuanalatCommandLineInterfaceseperticURLatauHTTPieataupuntoolyanglebihramahsepertiPostmandanbisajugaandamembangunantarmukawebdenganmemakaiAPIyangdisediakanolehserverPersonini.ContohpengetesanuntukaplikasiPersonRESTinibisalihatpadasub-babPengetesan.
AplikasiWebNode.js
85CaraKerja
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'),
AplikasiWebNode.js
86Server
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({
AplikasiWebNode.js
87Server
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,MongooseandMongoDB.'+
'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'});
}
})
});
//GET/persons/:username
AplikasiWebNode.js
88Server
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,rawResponse){
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"});
}
});
AplikasiWebNode.js
89Server
});
app.listen(app.get('PORT'));
console.log("ServerPort:"+app.get('PORT'));
AplikasiWebNode.js
90Server
PengetesanUntukmenggunakanataupengetesanAPIinicaratermudahadalahdenganmemakaiPostmanataujikaandasudahterbiasamemakaitoolterminalseperticURLatauHttpiesilahkansaja.
Demoaplikasiberadapadalinkberikut,
persons-api.herokuapp.com
POST/personsUntukmembuatdataPersonbarumelaluiapi/personscukupdenganmemakairequestPOST.
GET/persons
AplikasiWebNode.js
91Pengetesan
MengambildatadenganmengaksesAPI/personsyangakanmengembalikansemuadatayangtelahtersimpansebelumnya.
PUT/persons/:usernameUpdatedatabisadilakukandenganmudahdenganmemakaiPUT.
AplikasiWebNode.js
92Pengetesan
DELETE/persons/:usernameOperasipenghapusandatahanyabisadilakukansatupersatumelaluikey:username.
AplikasiWebNode.js
93Pengetesan
ImageUploader
Aplikasiinisangatsederhana,carakerjanyayaitugambardiuploadkeserverdankemudianditampilkankembalikebrowser.
ServerPadasisiserveraplikasiinimemakaiframeworkExpressJSuntukmenanganirequestHTTPdanpaketformidableuntukmenanganifileyangdiupload.
Catatan:AplikasiinimemakaisedikitfiturES6sepertilet,const,arrowfunctionsehinggaandaperlumenginstallsetidaknyaNode.jsv4.2.1LTS
AplikasiWebNode.js
95ImageUploader
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
AplikasiWebNode.js
96ImageUploader
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
AplikasiWebNode.js
97ImageUploader
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.
AplikasiWebNode.js
98ImageUploader
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
AplikasiWebNode.js
99MemakaiES6
'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.
AplikasiWebNode.js
100MemakaiES6
TentangPengarangEquanPr.adalahdeveloperNodeJSdanpeminumkopikelasberat.SelalusibukdenganyangberbauJavaScriptketikadidepankomputer,penggilafilm&musikmetaldankadang-kadangnge-twitdi@junwatuataunge-Github.
AplikasiWebNode.js
102TentangPengarang