Advertisement
Guest User

Untitled

a guest
Jan 9th, 2018
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.26 KB | None | 0 0
  1. Lahko pa si tudi pripravimo JSON datoteko ter vse podatke uvozimo z naslednjim
  2. ukazom:
  3. > mongoimport ‐‐db edugeocache ‐‐collection Lokacije ‐‐mode upsert ‐‐upsertFields naziv ‐‐jsonArray ‐‐file ~/workspace/sp‐2017‐2018‐edugeocache/testni_podatki.json
  4. 2017‐11‐17T12:51:09.932+0000 connected to: localhost
  5. 2017‐11‐17T12:51:09.940+0000 imported 3 documents
  6. Ker pri takšnem uvozu podatkov odvisni dokumenti nimajo polja _id , jih je potrebno
  7. pri komentarjih dodati.
  8. $ mongo
  9. > use edugeocache
  10. > db.Lokacije.find().forEach(function(dokument) {
  11. for (var i = 0; i < dokument.komentarji.length; i++) {
  12. dokument.komentarji[i]._id = ObjectId()
  13. }
  14. db.Lokacije.update({ "_id" : dokument._id }, dokument)
  15. })
  16. 11.1.5 Vključitev podatkovne baze
  17. 11.1.5.1 Gostovanje MongoDB podatkovne baze na mLab
  18. Uporabljali bomo ponudnika MongoDB podatkovne baze v oblaku mLab, ki v okviru
  19. sandbox dostopa omogoča brezplačno uporabo 1 podatkovne baze z do 500 Mb
  20. podatkov.
  21. Ko je registracija uspešna in elektronski naslov potrjen, kreiramo novo podatkovno
  22. bazo tipa sandbox. Podatkovno bazo poimenujemo edugeocache ter dodamo
  23. uporabnika user z geslom pass ter pridobimo povezavo do podatkovne baze, ki je v
  24. naslednji obliki:
  25. mongodb://user:pass@ds113136.mlab.com:13136/edugeocache
  26. Z naslednjim ukazom lahko iz lokalnega Cloud9 okolja preverimo delovanje naše
  27. oddaljene MongoDB podatkovne baze, ki jo gostujemo na mLab.
  28. 1/9/2018 Spletno programiranje 2017/2018
  29. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 23/45
  30. $ mongo ds113136.mlab.com:13136/edugeocache ‐u user ‐p pass
  31. MongoDB shell version v3.4.10
  32. connecting to: mongodb://ds113136.mlab.com:13136/edugeocache
  33. MongoDB server version: 3.4.9
  34. Namig: Bodite pozorni na to, da je verzija vašega odjemalca (MongoDB shell)
  35. novejša od verzije strežnika (MongoDB server), sicer lahko imate težave.
  36. Nato podatkovno bazo dodamo v parametre Heroku okolja, kar bomo kasneje
  37. potrebovali v aplikaciji, ko se bomo povezovali na podatkovno bazo
  38. $ heroku config:set MLAB_URI=mongodb://user:pass@ds113136.mlab.com:13136/edugeocache
  39. Setting MLAB_URI and restarting ⬢ edugeocache‐sp‐2017‐2018... done, v6
  40. MLAB_URI: mongodb://user:pass@ds113136.mlab.com:13136/edugeocache
  41. 11.1.5.2 Prenos podatkov iz lokalne podatkovne baze na mLab
  42. Ko imamo vzpostavljeno produkcijsko verzijo podatkovne baze na mLab, je potrebno
  43. vzpostaviti mehanizem za prenos podatkov iz razvojne verzije v produkcijsko verzijo
  44. podatkovne baze.
  45. Najprej kreiramo začasno mapo, kamor bomo shranili podatke razvojne verzije
  46. podatkovne baze.
  47. $ mkdir ‐p ~/workspace/mongodb/dump
  48. Potem naredimo posnetek stanja lokalne podatkovne baze v Cloud9 razvojnem
  49. okolju.
  50. $ mongodump ‐h localhost:27017 ‐d edugeocache ‐o ~/workspace/mongodb/dump
  51. 2017‐11‐17T21:11:29.515+0000 writing edugeocache.Lokacije to
  52. 2017‐11‐17T21:11:29.517+0000 done dumping edugeocache.Lokacije (3 documents)
  53. Sedaj pa obnovimo vsebino razvojne podatkovne baze na produkcijsko verzijo
  54. podatkovne baze na mLab.
  55. 1/9/2018 Spletno programiranje 2017/2018
  56. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 24/45
  57. $ mongorestore ‐h ds113136.mlab.com:13136 ‐d edugeocache ‐u user ‐p pass ~/workspace/mongodb/dump/edugeocache
  58. 2017‐11‐17T21:18:15.912+0000 building a list of collections to restore from /home/ubuntu/workspace/mongodb/dump/edugeocache dir
  59. 2017‐11‐17T21:18:15.931+0000 reading metadata for edugeocache.Lokacije from /home/ubuntu/workspace/mongodb/dump/edugeocache/Lokacije.metadata.json
  60. 2017‐11‐17T21:18:15.999+0000 restoring edugeocache.Lokacije from /home/ubuntu/workspace/mongodb/dump/edugeocache/Lokacije.bson
  61. 2017‐11‐17T21:18:16.033+0000 restoring indexes for collection edugeocache.Lokacije from metadata
  62. 2017‐11‐17T21:18:16.051+0000 finished restoring edugeocache.Lokacije (3 documents)
  63. 2017‐11‐17T21:18:16.051+0000 done
  64. Povežimo se na oddaljeno produkcijsko podatkovno bazo na mLab in preverimo, ali so
  65. podatki na voljo.
  66. $ mongo ds113136.mlab.com:13136/edugeocache ‐u user ‐p pass
  67. MongoDB shell version v3.4.10
  68. connecting to: mongodb://ds113136.mlab.com:13136/edugeocache
  69. MongoDB server version: 3.4.9
  70. > show collections
  71. Lokacije
  72. system.indexes
  73. > db.Lokacije.find()
  74. Če je bil uvoz uspešen, se nam prikažejo vsi podatki, ki smo jih že vnesli v lokalno
  75. razvojno podatkovno bazo v okolju Cloud9.
  76. 11.1.5.3 Izbira podatkovne baze glede na razvojno okolje
  77. V tem trenutku imamo tako vzpostavljeno ločeno razvojno in produkcijsko razvojno
  78. okolje, ki imata vsaka svojo podatkovno bazo, kot prikazuje slika 11.8.
  79. 1/9/2018 Spletno programiranje 2017/2018
  80. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 25/45
  81. Slika 11.8: Razvojno in produkcijsko razvojno okolje, vsako s svojo podatkovno bazo
  82. Glede na naš cilj ločitve razvojnih okolij, mora naša aplikacija v razvojnem okolju
  83. uporabljati lokalno podatkovno bazo, v produkcijskem okolju na Heroku pa podatkovno
  84. bazo, ki gostuje na mLab.
  85. To bomo dosegli z uporabo spremenljivke NODE_ENV v okolju Node.js.
  86. Privzeto je Heroku nastavljen na produkcijsko okolje, z naslednjim ukazom pa to še
  87. eksplicitno zahtevamo.
  88. $ heroku config:set NODE_ENV=production
  89. Setting NODE_ENV and restarting ⬢ edugeocache‐sp‐2017‐2018... done, v7
  90. NODE_ENV: production
  91. V datoteko db.js dodamo pogoj, kjer preverjamo, ali se aplikacija izvaja v
  92. produkcijskem okolju. Pri zagonu aplikacije preprosto preverjamo, ali ima okoljska
  93. spremenljivka NODE_ENV nastavljeno vrednost na production (glej vrstico 4), saj bomo
  94. takrat uporabili povezovalni niz na produkcijsko podatkovno bazo na mLab, ki je
  95. opredeljena v okoljski spremenljivki MLAB_URI (glej vrstico 5).
  96. app_server/models/db.js
  97. 1
  98. 2
  99. 3
  100. 4
  101. 5
  102. 6
  103. 7
  104. var mongoose = require('mongoose');
  105. var dbURI = 'mongodb://localhost/edugeocache';
  106. + if (process.env.NODE_ENV === 'production') {
  107. + dbURI = process.env.MLAB_URI;
  108. + }
  109. mongoose.connect(dbURI, { useMongoClient: true });
  110. 1/9/2018 Spletno programiranje 2017/2018
  111. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 26/45
  112. Uporabniškega imena in gesla za dostop do oddaljene MongoDB podatkovne baze, ki
  113. jo gostujemo na mLab, ne razkrivamo v izvorni kodi, ampak uporabimo spremenljivko
  114. MLAB_URI , ki smo jo predhodno nastavili na Heroku okolju.
  115. 11.1.5.4 Testiranje delovanja
  116. Če aplikacijo poženemo v razvojnem okolju, vidimo iz izpisov, da smo se povezali z
  117. lokalno podatkovno bazo.
  118. $ nodemon
  119. ...
  120. Mongoose je povezan na mongodb://localhost/edugeocache
  121. Sedaj preverimo še povezovanje na produkcijsko podatkovno bazo na mLab, kjer pred
  122. zagonom aplikacije z nodemon nastavimo okoljski spremenljivki NODE_ENV in
  123. MLAB_URI .
  124. $ NODE_ENV=production MLAB_URI=mongodb://user:pass@ds113136.mlab.com:13136/edugeocache nodemon start
  125. ...
  126. Mongoose je povezan na mongodb://user:pass@ds113136.mlab.com:13136/edugeocache
  127. Sedaj še preverimo delovanje v celoti na Heroku produkcijskem okolju.
  128. $ git add .
  129. $ git commit ‐m "Dodajanje mLab podatkovne baze"
  130. $ git push heroku master
  131. Z ukazom heroku logs lahko preverimo dnevniške zapise na oddaljenem Heroku
  132. strežniku in poiščemo vrstico, kjer je zapisano, da se je aplikacija povezala s
  133. produkcijsko podatkovno bazo na mLab.
  134. $ heroku logs
  135. ...
  136. 2017‐11‐17T21:48:52.223480+00:00 app[web.1]: Mongoose je povezan na mongodb://user:pass@ds113136.mlab.com:13136/edugeocache
  137. 1/9/2018 Spletno programiranje 2017/2018
  138. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 27/45
  139. 11.2 Priprava REST API­ja za dostop do
  140. MongoDB podatkovne baze
  141. Do tega trenutka smo vzpostavili MongoDB podatkovno bazo, vendar lahko do nje
  142. dostopamo zgolj preko ukazne vrstice. V nadaljevanju bomo zgradili REST API (glej
  143. sliko 11.9), ki nam bo omogočal interakcijo s podatkovno bazo s pomočjo HTTP zahtev
  144. ter izvajal standardne CRUD operacije.
  145. Slika 11.9: V nadaljevanju bomo s pomočjo Express, Node.js in Mongoose zgradili
  146. REST API za dostop do MongoDB podatkovne baze
  147. 11.2.1 REST API
  148. REST je bolj arhitekturni stil kot striktno določen protokol. REST je brez stanja, t.j.
  149. stanja oz. zgodovine trenutnega uporabnika se ne zaveda.
  150. API omogoča aplikacijam medsebojno komunikacijo.
  151. Iz tega izhaja, da je REST API vmesnik do aplikacije, brez stanja. V našem primeru
  152. bomo s pomočjo tega pristopa implementirali dostop do podatkovne baze. Pri
  153. osnovnem delovanju REST API pričakuje zahtevo, ki se na strani strežnika obdela (po
  154. potrebi dostopa do podatkovne baze) in vrne odgovor, kot je prikazano na sliki 11.10.
  155. 129
  156. 130
  157. 131
  158. 1/9/2018 Spletno programiranje 2017/2018
  159. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 28/45
  160. Slika 11.10: Zaporedje procesiranja pri REST zahtevi
  161. 11.2.2 URL zahteva
  162. Kot že omenjeno, želimo z REST API­jem implementirati standardne CRUD operacije:
  163. dodajanje novega elementa,
  164. branje seznama več elementov,
  165. branje določenega elementa,
  166. posodabljanje določenega elementa,
  167. brisanje določenega elementa.
  168. Za obvladovanje podatkov v zvezi z lokacijami bomo potrebovali akcije,
  169. predstavljene v tabeli 11.1.
  170. 1/9/2018 Spletno programiranje 2017/2018
  171. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 29/45
  172. Tabela 11.1: URL naslovi in parametri REST API­ja za lokacijo
  173. Akcija
  174. URL
  175. naslov
  176. Parametri Primer
  177. Kreiranje
  178. nove
  179. lokacije
  180. /lokacije http://edugeocache.si/api/lokacije
  181. Branje
  182. seznama
  183. lokacij
  184. /lokacije http://edugeocache.si/api/lokacije
  185. Branje
  186. določene
  187. lokacije
  188. /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  189. Posodobitev
  190. določene
  191. lokacije
  192. /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  193. Brisanje
  194. določene
  195. lokacije
  196. /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  197. Kot je razvidno iz tabele 11.1 ima vsaka akcija isti URL naslov, medtem ko 3 akcije
  198. pričakujejo tudi dodatni parameter za določitev točne lokacije.
  199. 11.2.3 Metoda zahteve
  200. Če želimo uporabiti isti URL naslov za vse akcije, je za medsebojno razlikovanje
  201. potrebno uporabiti različne metode zahtev, ki so predstavljene v tabeli 11.2. Pri metodi
  202. zahteve gre za navodilo strežniku, kakšno akcijo naj izvede.
  203. 1/9/2018 Spletno programiranje 2017/2018
  204. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 30/45
  205. Tabela 11.2: Metode zahteve, ki se uporabljajo pri REST API
  206. Metoda
  207. zahteve
  208. Uporaba Odgovor
  209. POST
  210. Dodajanje novega dokumenta v
  211. podatkovno bazo.
  212. Nov podatkovni objekt v
  213. podatkovni bazi.
  214. GET
  215. Branje obstoječega dokumenta iz
  216. podatkovne baze.
  217. Objekt, ki predstavlja odgovor
  218. na poizvedbo.
  219. PUT
  220. Posodabljanje dokumenta v
  221. podatkovni bazi.
  222. Posodobljen podatkovni objekt
  223. iz podatkovne baze.
  224. DELETE
  225. Brisanje obstoječega dokumenta
  226. iz podatkovne baze.
  227. NULL
  228. Če sedaj posodobimo tabelo 11.1 s podatki o metodah zahtev, dobimo naslednjo tabelo
  229. 11.3.
  230. Tabela 11.3: URL naslovi, parametri in metode REST API za lokacijo
  231. Akcija Metoda
  232. URL
  233. naslov
  234. Parametri Primer
  235. Kreiranje
  236. nove
  237. lokacije
  238. POST /lokacije http://edugeocache.si/api/lokacije
  239. Branje
  240. seznama
  241. lokacij
  242. GET /lokacije http://edugeocache.si/api/lokacije
  243. Branje
  244. določene
  245. lokacije
  246. GET /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  247. Posodobitev
  248. določene
  249. lokacije
  250. PUT /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  251. Brisanje
  252. določene
  253. lokacije
  254. DELETE /lokacije idLokacije http://edugeocache.si/api/lokacije/123
  255. 1/9/2018 Spletno programiranje 2017/2018
  256. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 31/45
  257. V tabeli 11.3 imamo osnovne metode, povezane z lokacijami, manjkajo pa nam še
  258. odvisni dokumenti, v našem primeru so to komentarji, ki so podrobneje opisani v
  259. tabeli 11.4.
  260. Tabela 11.4: URL naslovi, parametri in metode REST API za komentarje
  261. Akcija Metoda URL naslov Parametri Primer
  262. Kreiranje
  263. novega
  264. komentarja
  265. POST /lokacije/idLokacije/komentarji idLokacije
  266. http://edugeocache.si/api/
  267. lokacije/123/komentarji
  268. Branje
  269. določenega
  270. komentarja
  271. GET /lokacije/idLokacije/komentarji
  272. idLokacije ,
  273. idKomentarja
  274. http://edugeocache.si/api/
  275. lokacije/123/komentarji/abc
  276. Posodobitev
  277. določenega
  278. komentarja
  279. PUT /lokacije/idLokacije/komentarji
  280. idLokacije ,
  281. idKomentarja
  282. http://edugeocache.si/api/
  283. lokacije/123/komentarji/abc
  284. Brisanje
  285. določenega
  286. komentarja
  287. DELETE /lokacije/idLokacije/komentarji
  288. idLokacije ,
  289. idKomentarja
  290. http://edugeocache.si/api/
  291. lokacije/123/komentarji/abc
  292. 11.2.4 Odgovor (podatek in status) API­ja
  293. Dobra praksa pri uporabi API­ja je, da pri vsaki zahtevi dobimo odgovor, ki je sestavljen
  294. iz podatkov in HTTP šifre statusa. API podatke ponavadi vrača v XML ali JSON obliki.
  295. V našem primeru bomo uporabljali JSON obliko, ki je skladna z uporabljeno MEAN
  296. arhitekturo, prav tako pa zahteva prenos manjše količine podatkov kot XML oblika. Pri
  297. odgovoru odjemalec vedno pričakuje tudi HTTP šifro statusa, najbolj pogosto
  298. uporabljene so zbrane v tabeli 11.5.
  299. 1/9/2018 Spletno programiranje 2017/2018
  300. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 32/45
  301. Tabela 11.5: HTTP šifre statusa
  302. Šifra
  303. statusa
  304. Naziv Primer uporabe
  305. 200 OK Uspešna GET ali PUT zahteva.
  306. 201 Created Uspešna POST zahteva.
  307. 204 No content Uspešna DELETE zahteva.
  308. 400 Bad request
  309. Neuspešna GET , POST ali PUT zahteva, zaradi
  310. napačne vsebine.
  311. 401 Unauthorized
  312. Zahteva zaščitenega URL naslova z napačnimi
  313. prijavnimi podatki.
  314. 403 Forbidden Zahteva, ki ni dovoljena.
  315. 404 Not found
  316. Neuspešna zahteva, zaradi napačnega parametra
  317. v URL naslovu.
  318. 405
  319. Method not
  320. allowed
  321. Metoda zahteve ni dovoljena za zahtevan URL
  322. naslov.
  323. 409 Conflict
  324. Neuspešna POST zahteva, ko že obstaja objekt z
  325. istimi podatki.
  326. 500
  327. Internal server
  328. error
  329. Težava s strežnikom ali podatkovno bazo.
  330. Verjetno je največ uporabnikom poznana šifra statusa , ki predstavlja neuspešno
  331. zahtevo, ko določene strani, ki jo uporabnik zahteva, ni mogoče najti. Vendar to še
  332. zdaleč ni edina, ampak obstajajo še številne druge, povezane z napakami na strani
  333. odjemalca oz. strežnika, preusmeritve in uspešne zahteve, kot je razvidno iz tabele
  334. 11.5.
  335. 11.3 Implementacija API­ja z ogrodjem Express
  336. Aplikacijo smo že začeli graditi s pomočjo ogrodja Express, zdaj pa bi želeli dodati še
  337. dostop do podatkovne baze s pomočjo dostopa preko REST API­ja. Cilj je ločitev
  338. dostopa do podatkovne baze od aplikacije, zato bomo celotno izvorno kodo, povezano
  339. z implementacijo API­ja, hranili v mapi app_api .
  340. 404
  341. 1/9/2018 Spletno programiranje 2017/2018
  342. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 33/45
  343. $ cd ~/workspace/edugeocache
  344. $ mkdir app_api
  345. $ cd app_api
  346. $ mkdir routes
  347. $ mkdir controllers
  348. 11.3.1 Priprava usmerjevalnika
  349. V začetno datoteko naše aplikacije app.js dodamo referenco na usmerjevalnik v
  350. okviru implementacije API­ja.
  351. app.js
  352. 10
  353. 11
  354. 12
  355. var index = require('./app_server/routes/index');
  356. + var indexApi = require('./app_api/routes/index');
  357. var users = require('./app_server/routes/users');
  358. V aplikacijo dodamo tudi preusmeritev vseh zahtev /api na pravkar opredeljen
  359. usmerjevalnik indexApi .
  360. app.js
  361. 22
  362. 23
  363. 24
  364. app.use('/', index);
  365. + app.use('/api', indexApi);
  366. app.use('/users', users);
  367. Nato kreiramo novo datoteko app_api/routes/index.js , kjer bo implementiran
  368. usmerjevalnik za API. Izvorna koda usmerjevalnika je neposredna implementacija
  369. predvidenih poti za lokacije (glej tabelo 11.3 in vrstice 6 ­ 11) in komentarje (glej
  370. tabelo 11.4 in vrstice 13 ­ 21).
  371. app_api/routes/index.js
  372. 1/9/2018 Spletno programiranje 2017/2018
  373. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 34/45
  374. 1
  375. 2
  376. 3
  377. 4
  378. 5
  379. 6
  380. 7
  381. 8
  382. 9
  383. 10
  384. 11
  385. 12
  386. 13
  387. 14
  388. 15
  389. 16
  390. 17
  391. 18
  392. 19
  393. 20
  394. 21
  395. 22
  396. 23
  397. var express = require('express');
  398. var router = express.Router();
  399. var ctrlLokacije = require('../controllers/lokacije');
  400. var ctrlKomentarji = require('../controllers/komentarji');
  401. // Lokacije
  402. router.get('/lokacije', ctrlLokacije.lokacijeSeznamPoRazdalji);
  403. router.post('/lokacije', ctrlLokacije.lokacijeKreiraj);
  404. router.get('/lokacije/:idLokacije', ctrlLokacije.lokacijePreberiIzbrano)
  405. router.put('/lokacije/:idLokacije', ctrlLokacije.lokacijePosodobiIzbrano
  406. router.delete('/lokacije/:idLokacije', ctrlLokacije.lokacijeIzbrisiIzbrano
  407. // Komentarji
  408. router.post('/lokacije/:idLokacije/komentarji',
  409. ctrlKomentarji.komentarjiKreiraj);
  410. router.get('/lokacije/:idLokacije/komentarji/:idKomentarja',
  411. ctrlKomentarji.komentarjiPreberiIzbranega);
  412. router.put('/lokacije/:idLokacije/komentarji/:idKomentarja',
  413. ctrlKomentarji.komentarjiPosodobiIzbranega);
  414. router.delete('/lokacije/:idLokacije/komentarji/:idKomentarja',
  415. ctrlKomentarji.komentarjiIzbrisiIzbranega);
  416. module.exports = router;
  417. Pri opredelitvi API URL naslova se pogosto uporabljajo parametri, s katerimi določimo
  418. odvisne dokumente, kot je to v našem primeru komentarjev, ki so odvisni od lokacije.
  419. Vključitev parametra v URL naslov je preprosta in sicer imenu spremenljivke samo
  420. dodamo predpono dvopičja : .
  421. 11.3.2 Priprava osnutka krmilnika
  422. Pri pripravi osnutka usmerjevalnika moramo pripraviti začetno kodo, da bo API sploh
  423. deloval, funkcionalnosti pa dejansko v krmilniku ne bo implementirane nobene, zgolj
  424. vračanje enostavnega besedila uspešno . Pri tem bomo uporabili preprosto metodo
  425. vrniJsonOdgovor , ki mu bomo podali parametra status odgovora in vsebina
  426. odgovora.
  427. V nadaljevanju bomo zato pripravili metode v obeh krmilnikih
  428. app_api/controllers/lokacije.js in app_api/controllers/komentarji.js .
  429. app_api/controllers/lokacije.js
  430. 1/9/2018 Spletno programiranje 2017/2018
  431. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 35/45
  432. 1
  433. 2
  434. 3
  435. 4
  436. 5
  437. 6
  438. 7
  439. 8
  440. 9
  441. 10
  442. 11
  443. 12
  444. 13
  445. 14
  446. 15
  447. 16
  448. 17
  449. 18
  450. 19
  451. 20
  452. 21
  453. 22
  454. 23
  455. 24
  456. var vrniJsonOdgovor = function(odgovor, status, vsebina) {
  457. odgovor.status(status);
  458. odgovor.json(vsebina);
  459. };
  460. module.exports.lokacijeSeznamPoRazdalji = function(zahteva, odgovor) {
  461. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  462. };
  463. module.exports.lokacijeKreiraj = function(zahteva, odgovor) {
  464. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  465. };
  466. module.exports.lokacijePreberiIzbrano = function(zahteva, odgovor) {
  467. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  468. };
  469. module.exports.lokacijePosodobiIzbrano = function(zahteva, odgovor) {
  470. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  471. };
  472. module.exports.lokacijeIzbrisiIzbrano = function(zahteva, odgovor) {
  473. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  474. };
  475. app_api/controllers/komentarji.js
  476. 1
  477. 2
  478. 3
  479. 4
  480. 5
  481. 6
  482. 7
  483. 8
  484. 9
  485. 10
  486. 11
  487. 12
  488. 13
  489. 14
  490. 15
  491. 16
  492. 17
  493. 18
  494. 19
  495. 20
  496. var vrniJsonOdgovor = function(odgovor, status, vsebina) {
  497. odgovor.status(status);
  498. odgovor.json(vsebina);
  499. };
  500. module.exports.komentarjiKreiraj = function(zahteva, odgovor) {
  501. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  502. };
  503. module.exports.komentarjiPreberiIzbranega = function(zahteva, odgovor) {
  504. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  505. };
  506. module.exports.komentarjiPosodobiIzbranega = function(zahteva, odgovor)
  507. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  508. };
  509. module.exports.komentarjiIzbrisiIzbranega = function(zahteva, odgovor) {
  510. vrniJsonOdgovor(odgovor, 200, {"status": "uspešno"});
  511. };
  512. 11.3.3 Vključitev modela
  513. 1/9/2018 Spletno programiranje 2017/2018
  514. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 36/45
  515. Za API je ključnega pomena, da ima dostop do podatkovne baze, saj nam v
  516. nasprotnem primeru ne bi veliko koristil. Dostop do podatkovne baze imamo omogočen
  517. preko modelov, ki pa so trenutno vključeni v strežniško aplikacijo, ki se nahaja v mapi
  518. app_server . Ta strežniška aplikacija neposrednega dostopa do podatkovne baze
  519. preko modelov ne bo potrebovala, saj bo do podatkov dostopala posredno preko API
  520. vmesnika. Zaradi tega lahko prenesemo celotno mapo z modeli iz
  521. app_server/models v app_api/models .
  522. $ mv ~/workspace/edugeocache/app_server/models ~/workspace/edugeocache/app_api/models
  523. Zato moramo popraviti poti v osrednji aplikaciji app.js .
  524. app.js
  525. 8 * require('./app_api/models/db');
  526. Nato dodamo odvisnost v krmilnike API­ja v datotekah
  527. app_api/controllers/lokacije.js in app_api/controllers/komentarji.js .
  528. app_api/controllers/lokacije.js
  529. 1
  530. 2
  531. + var mongoose = require('mongoose');
  532. + var Lokacija = mongoose.model('Lokacija');
  533. app_api/controllers/komentarji.js
  534. 1
  535. 2
  536. + var mongoose = require('mongoose');
  537. + var Lokacija = mongoose.model('Lokacija');
  538. 11.3.4 Testiranje
  539. Za testiranje enostavnih GET zahtev lahko uporabimo kar spletni brskalnik, kamor
  540. vnesemo željeni URL naslov in dobimo pričakovan odgovor, kot je to prikazano na sliki
  541. 11.11.
  542. 1/9/2018 Spletno programiranje 2017/2018
  543. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 37/45
  544. Slika 11.11: Testiranje REST API GET zahteve /lokacije/1234
  545. Za bolj kompleksno testiranje vseh metod API vmesnika pa priporočamo bolj napredno
  546. orodje, kot je npr. Postman, ki nam omogoča napredno simuliranje različnih REST
  547. klicev in je v osnovni različici na voljo brezplačno.
  548. 11.4 GET metode za branje podatkov iz
  549. MongoDB
  550. Get metode se pri REST API vmesniku uporabljajo za poizvedovanje po podatkovni
  551. bazi in vračanje rezultatov poizvedb. V našem primeru imamo v usmerjevalniku
  552. app_api/routers/index.js opredeljene 3 GET metode, kot je prikazano v tabeli 11.6.
  553. Tabela 11.6: 3 GET metode v okviru aplikacije edugeocache
  554. Akcija Metoda URL naslov Parametri Primer
  555. Branje
  556. seznama
  557. lokacij
  558. GET /lokacije
  559. http://edugeocache.si/api/
  560. lokacije
  561. Branje
  562. določene
  563. lokacije
  564. GET /lokacije idLokacije
  565. http://edugeocache.si/api/
  566. lokacije/123
  567. Branje
  568. določenega
  569. komentarja
  570. GET /lokacije/idLokacije/komentarji
  571. idLokacije ,
  572. idKomentarja
  573. http://edugeocache.si/api/
  574. lokacije/123/komentarji/abc
  575. 11.4.1 Iskanje dokumenta
  576. Mongoose dostopa do podatkovne baze preko modelov, kar je tudi razlog, da smo
  577. model Lokacije vključili v oba krmilnika app_api/controllers/komentarji.jsi in
  578. app_api/controllers/lokacije.js .
  579. 1/9/2018 Spletno programiranje 2017/2018
  580. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 38/45
  581. MongoDB preko dostopa z Mongoose ima na voljo številne metode za iskanje
  582. podatkov, kjer so ključne naslednje:
  583. find se uporablja za splošno iskanje, glede na podan filter iskanja,
  584. findById išče dokument s podanim enoličnim identifikatorjem,
  585. findOne vrne prvi rezultat ujemanja podanega filtra iskanja,
  586. geoNear išče zadetke, ki so geografsko blizu podani zemljepisni širini in dolžini,
  587. geoSearch vključi dodatne omejitve pri iskanju geoNear .
  588. Za potrebe iskanja določene lokacije bomo uporabili metodo findById .
  589. app_api/controllers/lokacije.js
  590. 17
  591. 18
  592. 19
  593. 20
  594. 21
  595. 22
  596. 23
  597. + module.exports.lokacijePreberiIzbrano = function(zahteva, odgovor) {
  598. + Lokacija
  599. + .findById(zahteva.params.idLokacije)
  600. + .exec(function(napaka, lokacija) {
  601. * vrniJsonOdgovor(odgovor, 200, lokacija);
  602. + })
  603. + };
  604. Sedaj lahko preverimo delovanje metode tako, da najprej ugotovimo ID lokacije iz
  605. MongoDB podatkovne baze.
  606. $ mongo
  607. MongoDB shell version v3.4.10
  608. connecting to: mongodb://127.0.0.1:27017
  609. MongoDB server version: 3.4.10
  610. > use edugeocache
  611. switched to db edugeocache
  612. > db.Lokacije.find()
  613. { "_id" : ObjectId("5a0edde9490d6caf4cf68227"), ... }
  614. Nato s pomočjo ID­ja dokumenta sestavimo zahtevo, ki nam vrne zahtevano lokacijo iz
  615. podatkovne baze preko REST API­ja.
  616. https://sp‐2017‐2018‐priprave‐dejanl.c9users.io/api/lokacije/5a0edde9490d6caf4cf68227
  617. 132
  618. 1/9/2018 Spletno programiranje 2017/2018
  619. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 39/45
  620. 11.4.1.1 Obvladovanje napak
  621. Trenutna težava naše implementacije je, da vrne zgolj uspešen odgovor, v primeru
  622. neuspešne zahteve pa ne. Dobra praksa pri pripravi API­ja je obvladovanje in lovljenje
  623. napak, zato moramo poskrbeti tudi za to in odjemalcu vedno vrniti odgovor, tudi ko
  624. pride do napake. V našem primeru lahko pride do naslednjih napak:
  625. med parametri zahteve ni idLokacije (glej vrstico 18),
  626. metoda findById ne vrne nobene lokacije (glej vrstice od 22 do 25) in
  627. med izvajanje metode findById pride do napake (glej vrstice od 26 do 28).
  628. app_api/controllers/lokacije.js
  629. 17
  630. 18
  631. 19
  632. 20
  633. 21
  634. 22
  635. 23
  636. 24
  637. 25
  638. 26
  639. 27
  640. 28
  641. 29
  642. 30
  643. 31
  644. 32
  645. 33
  646. 34
  647. 35
  648. 36
  649. module.exports.lokacijePreberiIzbrano = function(zahteva, odgovor) {
  650. + if (zahteva.params && zahteva.params.idLokacije) {
  651. Lokacija
  652. .findById(zahteva.params.idLokacije)
  653. .exec(function(napaka, lokacija) {
  654. + if (!lokacija) {
  655. + vrniJsonOdgovor(odgovor, 404, { "sporočilo":
  656. + "Ne najdem lokacije s podanim enoličnim identifikatorjem idLokacije."
  657. + return;
  658. + } else if (napaka) {
  659. + vrniJsonOdgovor(odgovor, 404, napaka);
  660. + return;
  661. + }
  662. * vrniJsonOdgovor(odgovor, 200, lokacija);
  663. });
  664. + } else {
  665. + vrniJsonOdgovor(odgovor, 404, { "sporočilo":
  666. + "Manjka enolični identifikator idLokacije"});
  667. + }
  668. + };
  669. 11.4.2 Iskanje odvisnega dokumenta
  670. Komentarji so v našem primeru shranjeni kot deli dokumenta lokacije (odvisni
  671. dokumenti), tako da moramo najprej poiskati lokacijo, nato pa v tem dokumentu
  672. poiskati ustrezen komentar. Pri implementaciji metode komentarjiPreberiIzbranega v
  673. krmilniku app_api/controllers/komentarji.js si lahko pomagamo z implementacijo
  674. metode lokacijePreberiIzbrano iz prejšnjega poglavja. Ker ne potrebujemo vseh
  675. podatkov lokacije, lahko že v poizvedbi z uporabo .select('atribut1 atribut2 ...')
  676. omejimo, katere podatke potrebujemo (glej vrstico 17). Prav tako je v okviru MongoDB
  677. na voljo metoda id , s pomočjo katere lahko iščemo odvisne dokumente glede na
  678. podan enolični identifikator (glej vrstico 30).
  679. 1/9/2018 Spletno programiranje 2017/2018
  680. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 40/45
  681. app_api/controllers/komentarji.js
  682. 13
  683. 14
  684. 15
  685. 16
  686. 17
  687. 18
  688. 19
  689. 20
  690. 21
  691. 22
  692. 23
  693. 24
  694. 25
  695. 26
  696. 27
  697. 28
  698. 29
  699. 30
  700. 31
  701. 32
  702. 33
  703. 34
  704. 35
  705. 36
  706. 37
  707. 38
  708. 39
  709. 40
  710. 41
  711. 42
  712. 43
  713. 44
  714. 45
  715. 46
  716. 47
  717. 48
  718. 49
  719. 50
  720. module.exports.komentarjiPreberiIzbranega = function(zahteva, odgovor)
  721. + if (zahteva.params && zahteva.params.idLokacije && zahteva.params.idKomentarja
  722. + Lokacija
  723. + .findById(zahteva.params.idLokacije)
  724. + .select('naziv komentarji')
  725. + .exec(
  726. + function(napaka, lokacija) {
  727. + var rezultat, komentar;
  728. + if (!lokacija) {
  729. + vrniJsonOdgovor(odgovor, 404, { "sporočilo":
  730. + "Ne najdem lokacije s podanim enoličnim identifikatorjem idLokacije."
  731. + return;
  732. + } else if (napaka) {
  733. + vrniJsonOdgovor(odgovor, 404, napaka);
  734. + return;
  735. + }
  736. + if (lokacija.komentarji && lokacija.komentarji.length > 0) {
  737. + komentar = lokacija.komentarji.id(zahteva.params.idKomentarja
  738. + if (!komentar) {
  739. + vrniJsonOdgovor(odgovor, 404, { "sporočilo":
  740. + "Ne najdem komentarja s podanim enoličnim identifikatorjem idKomentarja"
  741. + } else {
  742. + rezultat = {
  743. + lokacija: { naziv: lokacija.naziv, id: zahteva.params.
  744. + komentar: komentar
  745. + };
  746. * vrniJsonOdgovor(odgovor, 200, rezultat);
  747. + }
  748. + } else {
  749. + vrniJsonOdgovor(odgovor, 404, { "sporočilo": "Ne najdem nobenega komentarja."
  750. + }
  751. + }
  752. + )
  753. + } else {
  754. + vrniJsonOdgovor(odgovor, 404, { "sporočilo":
  755. + "Ne najdem zapisa, oba enolična identifikatorja idLokacije in idKomentarja sta zahtevana."
  756. + }
  757. };
  758. Sedaj lahko preverimo delovanje metode tako, da najprej ugotovimo ID lokacije in ID
  759. komentarja iz MongoDB podatkovne baze.
  760. 1/9/2018 Spletno programiranje 2017/2018
  761. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 41/45
  762. $ mongo
  763. MongoDB shell version v3.4.10
  764. connecting to: mongodb://127.0.0.1:27017
  765. MongoDB server version: 3.4.10
  766. > use edugeocache
  767. switched to db edugeocache
  768. > db.Lokacije.find()
  769. { "_id" : ObjectId("5a0edde9490d6caf4cf68227"), ... , "komentarji" : [ { "_id" : ObjectId(
  770. Nato s pomočjo ID­ja dokumenta sestavimo zahtevo, ki nam vrne zahtevano lokacijo iz
  771. podatkovne baze preko REST API­ja.
  772. https://sp‐2017‐2018‐priprave‐dejanl.c9users.io/api/lokacije/5a0edde9490d6caf4cf68227/komentarji/5a0eddf719cf41316c98ccb4
  773. 11.4.3 Geografsko iskanje več dokumentov
  774. Spletna stran aplikacije naj bi prikazala seznam zanimivih lokacij, glede na trenutni
  775. položaj uporabnika. MongoDB ima na voljo nekaj geografskih funkcij iskanja, ki nam
  776. bodo to opravilo olajšale.
  777. Zahteva za prikaz lokacij je opremljena s parametrom lng in lat , kot prikazuje
  778. naslednji primer zahteve.
  779. /api/lokacije?lng=15.271601&lat=46.219849&maxRazdalja=100
  780. Pri zahtevi imamo na voljo naslednje parametre:
  781. obvezni parameter lng predstavlja zemljepisno dolžino,
  782. obvezni parameter lat predstavlja zemljepisno širino in
  783. opcijski parameter maxRazdalja predstavlja omejitev iskanja, do katere največje
  784. razdalje (v km) od podane točke naj vrača rezultate (privzeta vrednost je 20 km).
  785. Pri izvajanju geografskih iskanj, moramo vedno poskrbeti za omejevanje števila
  786. rezultatov. V okviru iskanja po MongoDB podatkovni bazi imamo na voljo dve možnosti:
  787. 1/9/2018 Spletno programiranje 2017/2018
  788. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 42/45
  789. število zadetkov num in
  790. razdalja od začetne točke maxDistance , kjer je pričakovana vrednost v metrih (to
  791. smo uporabili v našem primeru).
  792. Celotna implementacija funkcije za prikaz najbližjih lokacij lokacijeSeznamPoRazdalji s
  793. pomočjo MongoDB funkcije geoNear je prikazana spodaj:
  794. app_api/controllers/lokacije.js
  795. 9
  796. 10
  797. 11
  798. 12
  799. 13
  800. 14
  801. 15
  802. 16
  803. 17
  804. 18
  805. 19
  806. 20
  807. 21
  808. 22
  809. 23
  810. 24
  811. 25
  812. 26
  813. 27
  814. 28
  815. 29
  816. 30
  817. 31
  818. 32
  819. 33
  820. 34
  821. 35
  822. 36
  823. 37
  824. 38
  825. 39
  826. 40
  827. 41
  828. 42
  829. 43
  830. 44
  831. 45
  832. module.exports.lokacijeSeznamPoRazdalji = function(zahteva, odgovor) {
  833. + var lng = parseFloat(zahteva.query.lng);
  834. + var lat = parseFloat(zahteva.query.lat);
  835. + var razdalja = parseFloat(zahteva.query.maxRazdalja);
  836. + razdalja = isNaN(razdalja) ? 20 : razdalja;
  837. + var tocka = {
  838. + type: "Point",
  839. + coordinates: [lng, lat]
  840. + };
  841. + var geoParametri = {
  842. + spherical: true,
  843. + maxDistance: razdalja * 1000,
  844. + num: 10
  845. + };
  846. + if ((!lng && lng !== 0) || (!lat && lat !== 0)) {
  847. + vrniJsonOdgovor(odgovor, 404, { "sporočilo": "Parametra lng and lat sta obvezna."
  848. + return;
  849. + }
  850. + Lokacija.geoNear(tocka, geoParametri, function(napaka, rezultati) {
  851. + var lokacije = [];
  852. + if (napaka) {
  853. + vrniJsonOdgovor(odgovor, 404, napaka);
  854. + } else {
  855. + rezultati.forEach(function(dokument) {
  856. + lokacije.push({
  857. + razdalja: dokument.dis / 1000,
  858. + naziv: dokument.obj.naziv,
  859. + naslov: dokument.obj.naslov,
  860. + ocena: dokument.obj.ocena,
  861. + lastnosti: dokument.obj.lastnosti,
  862. + _id: dokument.obj._id
  863. + });
  864. + });
  865. * vrniJsonOdgovor(odgovor, 200, lokacije);
  866. + }
  867. + });
  868. };
  869. Sedaj lahko preverimo delovanje metode s testno zahtevo, kjer kot začetno točko
  870. podamo GPS koordinate lokacije Stari grad Celje in zahtevamo lokacije v radiju 100
  871. km.
  872. https://sp‐2017‐2018‐priprave‐dejanl.c9users.io/api/lokacije?lng=15.271601&lat=46.219849
  873.  
  874. 1/9/2018 Spletno programiranje 2017/2018
  875. https://teaching.lavbic.net/SP/2017­2018/MongoDB­Mongoose­REST.html 43/45
  876. Kot odgovor dobimo pričakovana 2 zadetka, Stari grad Celje na razdalji 0 km in ZOO
  877. Ljubljana na razdalji ~ 64 km.
  878. [
  879. {
  880. "razdalja": 0,
  881. "naziv": "Stari grad Celje",
  882. "naslov": "Cesta na grad 78, 3000 Celje, Slovenija",
  883. "ocena": 3,
  884. "lastnosti": ["slikovit razgled", "vstopnina", "otrokom prijazno"],
  885. "_id": "5a0edde9490d6caf4cf68227"
  886. }, {
  887. "razdalja": 64.41779956859011,
  888. "naziv": "ZOO Ljubljana",
  889. "naslov": "Večna pot 70, 1000 Ljubljana, Slovenija",
  890. "ocena": 4,
  891. "lastnosti": [ "priporočljivo za otroke", "živali", "parkirišče je na voljo", "vstopnina"
  892. "_id": "5a0edde9490d6caf4cf68229"
  893. }
  894. ]
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement