Produced by Araxis Merge on 4/18/2019 5:55:21 PM Eastern Daylight Time. See www.araxis.com for information about Merge. This report uses XHTML and CSS2, and is best viewed with a modern standards-compliant browser. For optimum results when printing this report, use landscape orientation and enable printing of background images and colours in your browser.
# | Location | File | Last Modified |
---|---|---|---|
1 | MCCF_EDI_TAS_TASCore v2.0_Build_10.zip\MCCF_EDI_TAS_API_Core | README.md | Wed Apr 3 02:27:40 2019 UTC |
2 | MCCF_EDI_TAS_TASCore v2.0_Build_10.zip\MCCF_EDI_TAS_API_Core | README.md | Mon Apr 15 17:23:23 2019 UTC |
Description | Between Files 1 and 2 |
|
---|---|---|
Text Blocks | Lines | |
Unchanged | 4 | 1774 |
Changed | 3 | 6 |
Inserted | 0 | 0 |
Removed | 0 | 0 |
Whitespace | |
---|---|
Character case | Differences in character case are significant |
Line endings | Differences in line endings (CR and LF characters) are ignored |
CR/LF characters | Not shown in the comparison detail |
No regular expressions were active.
1 | # TAS API | |
2 | ||
3 | ## Install ing | |
4 | ||
5 | TAS API fu nctionalit y is desig ned to be run via Do cker in bo th product ion and, f or non-GFE developme nt (see be low notes for GFE se tup). | |
6 | ||
7 | While this is not re quired in developmen t, it grea tly simpli fies the w orkflow, e xpands cap abilities, adds secu rity emula tion, and enables en tire infra structures to be spu n up and d own togeth er. | |
8 | ||
9 | Building s upport for the TAS A PI is just the build ing of a s ingle bina ry from th e `./src` folde : | |
10 | ||
11 | docker build . - f Dockerfi le.dev -t tas/node8 | |
12 | ||
13 | > tas/node 8 is the b inary for all Node 8 work | |
14 | ||
15 | To setup p rerequisit es for the TAS API, run the fo llowing fr om the `./ src` folde r: | |
16 | ||
17 | docker run -v $P WD:/var/ap p tas/node 8 npm inst all | |
18 | ||
19 | Most comma nds will b e prefixed with `doc ker run -i t -v $PWD: /var/app`. | |
20 | ||
21 | ## Running | |
22 | ||
23 | With the ` tas/node8` binary bu ilt, run i t from `./ src`, spec ifying the code loca tion (`$PW D`) and th e port to use (3000) : | |
24 | ||
25 | docker run -it - v $PWD:/va r/app -p 3 000:3000 t as/node8 | |
26 | ||
27 | > By defau lt, tas/no de8 will r un PM2, wh ich will r un the API . See belo w for more examples that use o ther tools in the sa me binary. | |
28 | ||
29 | You can ad d environm ent variab les (`-e`) as needed . The foll owing will enable ve rbose outp ut for man y parts of the API: | |
30 | ||
31 | docker run -it - e "DEBUG=a pi,elastic ,azure,fs, core,memor y,webclien t,errors" -v $PWD:/v ar/app -p 3000:3000 tas/node8 | |
32 | ||
33 | > Common d ebug filte rs: `test, security, errors, h ttp, api, api-intern al, core, providers, elastic, azure` | |
34 | ||
35 | Set produc tion mode by setting the `NODE _ENV` envi ronment va riable. | |
36 | ||
37 | ### Tests | |
38 | ||
39 | Run tests with `moch a`: | |
40 | ||
41 | docker run -it - v $PWD:/va r/app tas/ node8 moch a | |
42 | ||
43 | With verbo se output: | |
44 | ||
45 | docker run -it - e "DEBUG=a pi,elastic ,azure,fs, core,memor y,webclien t,errors" -v $PWD:/v ar/app tas /node8 moc ha | |
46 | ||
47 | This will run tests in the `te st/` folde r. Running `mocha ta s/test` wi ll run TAS API inter nal tests. | |
48 | ||
49 | Run tests on save wi th `-w`. T his is hel pful durin g developm ent. | |
50 | ||
51 | A more com plete exam ple: | |
52 | ||
53 | docker run -v `pwd`: /var/app - e "DEBUG=a pi,api-int ernal,azur e,data,fs, core,memor y,webclien t,errors" -e "TAS_EN ABLE_HTTP= true" -e " TAS_ACTIVA TE=logging ,health,me trics" -e "TAS_PROVI DERS=LOGGI NG:memory, Metabase:a zure" -e " TAS_AZURE_ STORAGE_NA ME=tasstor age01" -e "TAS_AZURE _STORAGE_K EY=qv806MR EPLACE_WIT H_ACTUAL_K EYnDWQ==" -e "TAS_MO NGODB_CONN ECTION_STR ING=mongod b:// IP 7" -e "TAS _MONGODB_D ATABASE=te st tas/nod e8 mocha - w tas/test | |
54 | ||
55 | ## GFE Set up | |
56 | ||
57 | Developmen t using No de relies on events from the f ile system . When you save a fi le, PM2 wi ll automat ically rel oad your a pplication or Mocha will rerun all your tests. How ever, beca use the GF E VPN bloc ks traffic directly to a local VM, these events ar e never ra ised. Ther efore, Doc ker develo pment is n ot feasibl e on a GFE . | |
58 | ||
59 | > Merely r unning the API as a dependency (e.g. to support FH IR or the UI), the a forementio ned Docker setup is perfectly fine for r unning the API. | |
60 | ||
61 | To run the API for d evelopment , you setu p everythi ng directl y on the G FE: | |
62 | ||
63 | 1) Ensure Git for Wi ndows is i nstalled. | |
64 | ||
65 | 2) Start g it bash. | |
66 | ||
67 | 3) Run `gi t clone ss h://git@bi tbucket.or g/halfaker /mccf_tas_ api`, then move to ` src` folde r) | |
68 | ||
69 | 4) Run `np m install -g pm2@2.9 .3 mocha@4 .1.0` to s etup PM2 ( runs the A PI) and Mo cha (runs tests) | |
70 | ||
71 | 5) Run the following inside th e src fold er (most w ork will b e done in the src fo lder): `np m install` | |
72 | ||
73 | <<<<<<< HE AD | |
74 | ======= | |
75 | 6a) To run the API, run `pm2 s tart -x ta s/app.js`, but for a ny practic al work, y ou'll want to ensure a few env ironment v ariables a re set in that insta nce of the API, ther efore run: `DEBUG=ap i,memory T AS_IMPERSO NATE_SEC_I D=_0000111 11 TAS_ENA BLE_OVERRI DDEN_IAM_T RAITS=true TAS_ENVIR ONMENT=dev pm2 start -x tas/ap p.js --nam e=api`. Yo u will add and remov e modules from DEBUG throughou t your day -to-day de velopment. | |
76 | ||
77 | 6b) To run tests, th e environm ent variab les are th e same, bu t instead of pm2, yo u wil run mocha: `DE BUG=api,me mory TAS_I MPERSONATE _SEC_ID=_0 00011111 T AS_ENABLE_ OVERRIDDEN _IAM_TRAIT S=true TAS _ENVIRONME NT=dev moc ha` | |
78 | ||
79 | You can vi ew pm2 log s with `pm 2 logs api `. | |
80 | ||
81 | ### Enviro nment Vari ables | |
82 | ||
83 | >>>>>>> c8 d08cf6cfb3 01005470c8 d9540b2d29 2091613a | |
84 | * `DEBUG` - Node.js debugging module. Se e examples in this d ocument fo r usage. | |
85 | ||
86 | * `TAS_ENA BLE_HTTP` - set to ` true` to a llow HTTP calls. Whe n not set to `true`, HTTP call s will not occur. | |
87 | ||
88 | * `TAS_PRO VIDERS` - used to st ate which APIs use w hich dynam ic data pr oviders. D efault is `memory`. Example: ` TAS_PROVID ERS=LOGGIN G:memory,M etabase:az ure` | |
89 | ||
90 | * `TAS_APP LICATION_L OGIN_URL` - IAM logi n page; va ries per e nvironment | |
91 | ||
92 | * `TAS_ACT IVATE` - u sed to act ive only s pecific AP Is. For ex ample, one deploymen t may only have logg ing, but a nother may only have config. D efault is to activat e all endp oints. Exa mple: `TAS _ACTIVATE= logging,he alth,metri cs` | |
93 | ||
94 | The follow ing are en vironment variables used to sp ecify conn ection inf ormation. These exis t for each data prov ider. | |
95 | ||
96 | * `TAS_FIL ESYSTEM_DA TA_ROOT` - should no rmally be set to `/ var/log/ta s`; use Do cker volum e mapping to specify actual lo cation; ** NOT FOR PR ODUCTION U SE**. | |
97 | ||
98 | * `TAS_MON GODB_CONNE CTION_STRI NG` | |
99 | ||
100 | * `TAS_MON GODB_DATAB ASE` | |
101 | ||
102 | * `TAS_AZU RE_STORAGE _NAME` | |
103 | ||
104 | * `TAS_AZU RE_STORAGE _KEY` | |
105 | ||
106 | * `TAS_QUE UE_ADDRESS ` - Queue service ad dress; doe s not spec ify a spec ific queue . Example: `TAS_QUEU E_ADDRESS= amqp://tas -queue:567 2` | |
107 | ||
108 | ## Archite cture | |
109 | ||
110 | To ensure proper sep aration of concerns, layer bou ndaries ar e defined and decoup led. | |
111 | ||
112 | These laye rs include : activati on (analog ous to pre sentation) , core, an d data. | |
113 | ||
114 | The activa tion later is how fu nctionalit y is calle d (e.g. HT TP/AMQP), the core i s the busi ness funct ionality, and the da ta layer p rovides a dynamic pr ovider mod el to allo w simplifi ed data-ac cess. | |
115 | ||
116 | Future sec tions of t his docume nt will ex plain each in furthe r details. | |
117 | ||
118 |  | |
119 | ||
120 | ## Usage | |
121 | ||
122 | ### API Co mmands | |
123 | ||
124 | The primar y way to w ork with t he TAS API is via co mmands. Th ese abstra ct much of the under lying plum bing for b oth HTTP e ndpoints a nd AMQP. T hey're you r primary way of cre ating func tionality with the T AS API. | |
125 | ||
126 | Raw HTTP v erbs (e.g. GET, PATC H, POST) t ie your ap plication closely to a specifi c protocol and don't relate di rectly to business r equirement s. Command s are prot ocol agnos tic and ex pand your capabiliti es to stre tch to you r requirem ents. POST and PATCH do not ob vious rela te to busi ness requi rements, b ut "conver t", "trans late", "in crement" m ight. | |
127 | ||
128 | Focusing o n the desi gn of HTTP verb usag e distract s from the implement ation of b usiness re quirements and is un necessaril y limiting . Therefor e, it's be st to focu s on comma nds in the TAS API. | |
129 | ||
130 | Refer to v 3 of the e xample end point for a full in- line comma nd example (a better , more mod ular appro ach is dis cussed lat er). | |
131 | ||
132 | Consider t he followi ng snippet : | |
133 | ||
134 | const commands = new $tas. command.Re gistry() | |
135 | ||
136 | //+ pr e-defined, general u se command s | |
137 | const { Incremen tCommand, MultiplyCo mmand } = require('. ./commands ') | |
138 | ||
139 | comman ds | |
140 | .s tart('incr ement') | |
141 | .n ext(new In crementCom mand()) | |
142 | .e nd() | |
143 | ||
144 | This loads a series of predefi ned comman ds and add s their fu nctionalit y to an AP I endpoint . If the e ndpoint na me is `exa mple` usin g `data` ( see later section on namespace s and vers ioning), t hese could be access ed via the following paths: | |
145 | ||
146 | /api/c ore/exampl e/data/inc rement | |
147 | ||
148 | This comma nd model h elps to hi de abstrac t notions of HTTP ve rbs and al lows direc t implemen tation bas ed on requ irements. You aren't calling a n abstract "POST", y ou're call ing a conc rete "incr ement". | |
149 | ||
150 | Commands c an also be built inl ine withou t being de fined for reuse: | |
151 | ||
152 | //+ in line-creat ed command s | |
153 | comman ds.create( 'create', async (sc, values, a dapter) => adapter.c reateRespo nse($tas.c onstants.s tatus.SUCC ESS, await example.p ersist(sc, values))) | |
154 | comman ds.create( 'findById' , async (s c, values, adapter) => { | |
155 | tr y { | |
156 | const re sult = awa it example .getOne(sc .secid, va lues.id) | |
157 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, result) | |
158 | } | |
159 | ca tch (ex) { | |
160 | if (ex.m essage.ind exOf('not found') > -1) { | |
161 | retu rn adapter .createRes ponse($tas .constants .status.NO T_FOUND) | |
162 | } | |
163 | return a dapter.cre ateRespons e($tas.con stants.sta tus.ERROR, 'Unexpect ed error.' ) | |
164 | } | |
165 | }) | |
166 | comman ds.create( 'delete', async (sc, values, a dapter) => { | |
167 | aw ait exampl e.delete(s c.secid, v alues.id) | |
168 | re turn adapt er.createR esponse($t as.constan ts.status. NO_CONTENT ) | |
169 | }) | |
170 | ||
171 | These woul d be acces sible via the follow ing paths: | |
172 | ||
173 | /api/c ore/exampl e/data/cre ate | |
174 | /api/c ore/exampl e/data/fin dById | |
175 | /api/c ore/exampl e/data/del ete | |
176 | ||
177 | > Commands are not m eant to be tied to H TTP, thus the use of the adapt er. | |
178 | ||
179 | You would call this API as fol lows: | |
180 | ||
181 | POST / api/core/e xample/dat a/create | |
182 | ||
183 | BODY: { "a": 1, "b": 2, "c ": 3 } | |
184 | ||
185 | ### Comman d Manageme nt | |
186 | ||
187 | These comm ands can b e organize d into the ir own fil es, allowi ng for ind ependent G it version control a nd managem ent. These are the c ommands us ed in a pr evious exa mple. | |
188 | ||
189 | ./comm ands | |
190 | ./ fhir | |
191 | fhir-gro up-by.js | |
192 | fhir-que ry.js | |
193 | co ncat.js | |
194 | in crement.js | |
195 | in dex.js | |
196 | mu ltiply.js | |
197 | ||
198 | Each comma nd is in i ts own fil e, but is combined a nd exporte d in index .js (this is an arti fact of ho w Node.js works): | |
199 | ||
200 | "use s trict" | |
201 | ||
202 | const $tas = req uire('../. ./../tas') () | |
203 | ||
204 | //+ pr e-defined, general u se command s | |
205 | const fhir = req uire('./fh ir') | |
206 | const ConcatComm and = requ ire('./con cat') | |
207 | const IncrementC ommand = r equire('./ increment' ) | |
208 | const MultiplyCo mmand = re quire('./m ultiply') | |
209 | ||
210 | module .exports = { QueryCo mmand, fhi r, ConcatC ommand, In crementCom mand, Mult iplyComman d } | |
211 | ||
212 | ### Comman d Examples | |
213 | ||
214 | Consider t he followi ng command in its ow n file: | |
215 | ||
216 | class extends $t as.command .Command { | |
217 | as ync run(se curityCont ext, value s, adapter ) { | |
218 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, values. number + 1 ) | |
219 | } | |
220 | } | |
221 | ||
222 | Called wit h: | |
223 | ||
224 | POST / api/core/e xample/mod ular/incre ment | |
225 | ||
226 | BODY: { | |
227 | "n umber": 9 | |
228 | } | |
229 | ||
230 | This would call Incr ementComma nd and ret urn `{ "nu mber": 10 }`. | |
231 | ||
232 | Consider t he followi ng more pr actical ex ample: | |
233 | ||
234 | const $tas = req uire('../. ./../tas') () | |
235 | ||
236 | module .exports = class ext ends $tas. command.Co mmand { | |
237 | as ync run(se curityCont ext, value s, adapter ) { | |
238 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, await $ tas.fhir.c all(values .resource, values.pa rams, secu rityContex t)) | |
239 | } | |
240 | } | |
241 | ||
242 | This comma nd would b e accessed with the following (the comma nd name "f hir" is se t in the ` super('fhi r')` line in the pre vious exam ple): | |
243 | ||
244 | POST / api/core/e xample/v2/ fhir | |
245 | ||
246 | BODY: { | |
247 | "r esource": "Bundle", | |
248 | "p arams": { | |
249 | "locatio n": "001", | |
250 | "transac tion": "27 0", | |
251 | "_id": " 1" | |
252 | } | |
253 | } | |
254 | ||
255 | ### Comman d Pipeline s | |
256 | ||
257 | Commands c an also be run in se ries. Cons ider the f ollowing e xample: | |
258 | ||
259 | comman ds | |
260 | .s tart('ampl ify') | |
261 | .n ext(new In crementCom mand()) | |
262 | .n ext(new Mu ltiplyComm and()) | |
263 | .e nd() | |
264 | ||
265 | This examp le uses th e same Inc rementComm and shown previously , but also the follo wing: Mult iplyComman d: | |
266 | ||
267 | class extends $t as.command .Command { | |
268 | as ync run(_, values, a dapter) { | |
269 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, { numbe r: parseIn t(values.n umber) * 1 0 }) | |
270 | } | |
271 | } | |
272 | ||
273 | This will declare a publicly c ommand nam ed "amplif y". | |
274 | ||
275 | This would be called with: | |
276 | <<<<<<< HE AD | |
277 | ||
278 | ======= | |
279 | ||
280 | >>>>>>> c8 d08cf6cfb3 01005470c8 d9540b2d29 2091613a | |
281 | POST / api/core/e xample/v2/ amplify | |
282 | ||
283 | BODY: { "number" : 4 } | |
284 | ||
285 | The result will be ` { "number" : 50 }`. T his is bec ause Incre mentComman d will inc rement 4 t o 5, then Multiply w ill scale 5 to 50. | |
286 | ||
287 | Here's an example wi th data ac cess: | |
288 | ||
289 | comman ds | |
290 | .s tart('fhir -query') | |
291 | .n ext(new fh ir.FhirQue ryCommand( )) | |
292 | .n ext(new fh ir.FhirGro upByComman d()) | |
293 | .e nd() | |
294 | ||
295 | This pipel ine uses t he followi ng two com mands: | |
296 | ||
297 | `FhirQuery Command`: | |
298 | ||
299 | class extends $t as.command .Command { | |
300 | as ync run(se curityCont ext, value s, adapter ) { | |
301 | const tt l = $tas.c onstants.O NE_MINUTE * 5 | |
302 | const ke y = 'fhir: :' + JSON. stringify( values.res ource) + J SON.string ify(values .params) | |
303 | return $ tas.cache. build(key, async () => { | |
304 | retu rn adapter .createRes ponse($tas .constants .status.SU CCESS, awa it $tas.fh ir.call(va lues.resou rce, value s.params, securityCo ntext)) | |
305 | }, ttl) | |
306 | } | |
307 | } | |
308 | ||
309 | `FhirGroup ByCommand` : | |
310 | ||
311 | class extends $t as.command .Command { | |
312 | as ync run(_, values, a dapter) { | |
313 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, $tas.fh ir.groupBy ResourceTy pe(values) ) | |
314 | } | |
315 | } | |
316 | ||
317 | ||
318 | This would be called with: | |
319 | ||
320 | POST / api/core/e xample/mod ular/fhir- query | |
321 | ||
322 | BODY: | |
323 | { | |
324 | "resourc e": "Bundl e", | |
325 | "params" : { | |
326 | "loc ation": "0 01", | |
327 | "tra nsaction": "270", | |
328 | "_id ": "1" | |
329 | } | |
330 | } | |
331 | ||
332 | The result will be a n group ag gregation of FHIR da ta. | |
333 | ||
334 | Notice the FhirQuery Command co mmand has caching, t hus the re sults will return fa ster on su bsequent c alls. | |
335 | ||
336 | ### Queuei ng | |
337 | ||
338 | To enable queueing, a queue ad dress must be set vi a the appr opriate en vironment variable. Example: | |
339 | ||
340 | TAS_QU EUE_ADDRES S=amqp://1 27.0.0.1:5 672 | |
341 | ||
342 | Queueing r elates mor e to the p rotocol us ed than th e specific product s elected. P ut differe ntly, queu eing relat es to AMQP (`Advance d Message Queueing P rotocol`), not Rabbi tMQ. | |
343 | ||
344 | AMQP 0.9 a bstraction is built- in. | |
345 | ||
346 | To send to a queue, use the fo llowing: | |
347 | ||
348 | await $tas.provi ders.amqp. send(queue _name, obj ) | |
349 | ||
350 | This will send the u nmodified object to the queue. | |
351 | ||
352 | To attach the securi ty context (e.g. use r informat ion) to th e object, use the fo llowing: | |
353 | ||
354 | await $tas.provi ders.amqp. send(queue _name, sec urityConte xt, obj) | |
355 | ||
356 | This will add `$secu rityContex t` propert y to the o bject. | |
357 | ||
358 | To listen for messag es, use th e followin g: | |
359 | ||
360 | const callback = content = > { } | |
361 | await $tas.provi ders.amqp. listen(que ue_name, c allback) | |
362 | ||
363 | To configu re transpo rt securit y, set one or more o f the foll owing envi ronment va riable: | |
364 | ||
365 | * TAS_QUEU E_CERTIFIC ATE_PATH | |
366 | * TAS_QUEU E_KEY_PATH | |
367 | * TAS_QUEU E_CA_PATH | |
368 | * TAS_QUEU E_PASSPHRA SE | |
369 | ||
370 | If you hav e problems connectin g to a que ue, you ca n use Moch a to run ` tas/test/q ueue-troub leshooting .js`. This also serv es as a se ries of ex amples. | |
371 | ||
372 | #### Comma nd Queuein g | |
373 | ||
374 | Commands a lso provid e an abstr action lay er for que ues. | |
375 | ||
376 | Command qu eueing can be added to any end point with the follo wing segme nt taken f rom the ex ample endp oint: | |
377 | ||
378 | $tas.p roviders.a mqp.enable AmqpComman dListener( 'example-c ommands', require('. /commands/ amqp-dispa tcher')) | |
379 | ||
380 | This sets up the AMQ P command dispatcher on the 'e xample-com mands' que ue. | |
381 | ||
382 | Consider t he followi ng snippet from a AM QP command dispatche r: | |
383 | ||
384 | comman ds | |
385 | .s tart('scal e') | |
386 | .n ext(new In crementCom mand()) | |
387 | .n ext(new Mu ltiplyComm and()) | |
388 | .n ext(new Se ndCommand( )) | |
389 | .e nd() | |
390 | ||
391 | These use the previo us command s Incremen tCommand a nd Multipl yCommand, but also t he followi ng SendCom mand: | |
392 | ||
393 | class extends $t as.command .Command { | |
394 | as ync run(se curityCont ext, value s, adapter ) { | |
395 | const nu mber = par seInt(valu es.number) || 0 | |
396 | if (numb er < 10000 ) { | |
397 | awai t $tas.pro viders.amq p.send("ex ample-comm ands", sec urityConte xt, { "nam e": "scale ", "values ": { "numb er": numbe r } }) | |
398 | } | |
399 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, { numbe r: parseIn t(values.n umber) * 1 0 }) | |
400 | } | |
401 | } | |
402 | ||
403 | In order t o more cle arly expla in the exa mple, cons ider the f ollowing c ommand lis tening on HTTP: | |
404 | ||
405 | if ($t as.config. QUEUE_ADDR ESS) { | |
406 | co mmands.cre ate('scale ', async ( sc, values , adapter) => adapte r.createRe sponse($ta s.constant s.status.S UCCESS, aw ait $tas.p roviders.a mqp.send(" example-co mmands", s c, { name: 'scale', values }) || 0)) | |
407 | } | |
408 | ||
409 | > This com mand will only be re gistered i f the TAS_ QUEUE_ADDR ESS enviro nment vari able is se t. | |
410 | ||
411 | In this mo re advance d example, we're usi ng the fol lowing to call the A PI: | |
412 | ||
413 | POST / api/core/e xample/mod ular/scale | |
414 | ||
415 | BODY { "number": 4 } | |
416 | ||
417 | This will cause the command re gistered t o HTTP to send an in crement co mmand to t he `exampl e` queue. The AMQP d ispatcher will pick up the mes sage, incr ement it, multiply i t, then Se ndCommand will creat e another message to put in th e queue if the resul t is less than 10000 . | |
418 | ||
419 | This recur sive queue command e xample sho ws the fle xibility o f commands . | |
420 | ||
421 | Notice als o that the same comm ands are u sed betwee n HTTP and AMQP. Com mands are not tied t o protocol s. | |
422 | ||
423 | Command qu eues can b e helpful for things like logg ing, where they may be a very large set of data. | |
424 | ||
425 | As shown i n passing, you can c heck to se e if queue ing is con figured by checking the the `$ tas.config .QUEUE_ADD RESS` vari able: | |
426 | ||
427 | if ($t as.config. QUEUE_ADDR ESS) { } | |
428 | ||
429 | The format of the qu eue messag e will be in the fol lowing for mat: | |
430 | ||
431 | { $nam e, $conten t: { value s }, $secu rityContex t } | |
432 | ||
433 | ### Namesp aces | |
434 | ||
435 | API comman ds live in namespace s. Namespa ces provid e differen t surface areas with in an endp oint. A na mespace is the URI s egment tha t follows the endpoi nt name: | |
436 | ||
437 | /api/c ore/exampl e/NAMESPAC E/convert | |
438 | ||
439 | You can ha ve the sam e commands do differ ent things in differ ent namesp aces. "con vert" may have one m eaning in one namesp ace, but s omething e ntirely di fferent in another. For exampl e, a loggi ng endpoin t may have different logging t echniques for differ ent system s. /loggin g/fhir/cre ate may ac t differen tly than / logging/az ure/create . | |
440 | ||
441 | For public -facing AP Is, namesp aces can b e used to provide ve rsioning. However, v ersioning is differe nt than tr aditional software. This relat es to the fact that it can be very diffi cult for a consumer to switch APIs. Ther efore, eac h API vers ion should be treate d as a dif ferent pro duct. Ther e should b e very few API versi ons. | |
442 | ||
443 | > Rule of thumb: **a version i s required when the return obj ect change s**. It's generally more diffi cult to mo dify an ex isting API to return a differe nt data ty pe than to accept on e. The poi nt is that you want to maintai n backward compatibi lity until everyone has moves to the new version. Extending functional ity does n ot immedia tely call for a vers ion update ; do not c onfused Gi t versioni ng and app lication v ersioning with API v ersioning. | |
444 | ||
445 | ### Endpoi nts | |
446 | ||
447 | The endpoi nt is the fundamenta l unit of the API. E ach endpoi nt is isol ated from every othe r. If one endpoint b reaks, the others wi ll not fai l. Endpoin ts have na mespaces, which is w here comma nds live. An endpoin t is decla red by the `endpoint .js` file at the bas e of your endpoint f older. | |
448 | ||
449 | Here's a f ull exampl e of an en dpoint: | |
450 | ||
451 | const $tas = req uire('../. ./tas')() | |
452 | ||
453 | module .exports.i nit = (app , router) => { | |
454 | $t as.setupBi nding(rout er, 'examp le', async ns => { | |
455 | //+ mult iple names paces impl ies namesp ace routin g | |
456 | ns.regis ter("v1") | |
457 | ns.regis ter("v2") | |
458 | ns.regis ter("v3") | |
459 | }) | |
460 | } | |
461 | ||
462 | Inside the callback of the `$t as.setupBi nding` fun ction, you can setup additiona l listener s for you endpoint, such as an AMQP or W ebSocket l istener. | |
463 | ||
464 | # $tas obj ect | |
465 | ||
466 | All intera ctions wit hin the TA S API are done throu gh the `$t as` object . Once you load the `$tas` obj ect, no mo re file im ports are required t o access f oundationa l API func tionality. | |
467 | ||
468 | You access the objec t with the following : | |
469 | ||
470 | const $tas = req uire('../. ./tas')() | |
471 | ||
472 | > Your pat h will be relative t o where yo ur file is . | |
473 | ||
474 | One very c ommon use case is lo ading a da ta provide r: | |
475 | ||
476 | const example = $tas.provi ders.load( 'example') | |
477 | ||
478 | You can al so access a provider directly: | |
479 | ||
480 | const azure = $t as.provide rs.azure | |
481 | ||
482 | Another co mmon use c ase is loa ding a cor e | |
483 | ||
484 | const logging = $tas.core. load('logg ing') | |
485 | ||
486 | You also a ccess help ers via th e `$tas` o bject: | |
487 | ||
488 | const utility = $tas.helpe rs.utility | |
489 | const response = $tas.help ers.respon se | |
490 | const idgen = $t as.helpers .idgen | |
491 | ||
492 | Many of th ese helper s provide very commo n function ality: | |
493 | ||
494 | const camelCase = $tas.hel pers.text. toCamelCas e("ThisSta rtsAsPasca lCase") | |
495 | ||
496 | const cleanArray = $tas.he lpers.arra y.distinct ([1, 2, 3, 3, 3, 3, 3, 4, 5, 5 , 5]) | |
497 | ||
498 | const url = $tas .helpers.u ri.join(.. .['a', 'b' , 'c', 'd' ]) | |
499 | ||
500 | You can al so access caching vi a $tas: | |
501 | ||
502 | await $tas.cache .set('Meta base::' + name, valu e) | |
503 | ||
504 | let va lue = awai t $tas.cac he.get('Me tabase::' + name) | |
505 | ||
506 | > Cache is global, s o it's a g ood idea t o scope yo ur variabl es. For ex ample, not "timeout" , but "Met abase::tim eout". | |
507 | ||
508 | You can al so use cal l FHIR and parse obj ects with the $tas.f hir object . This has a number of methods , includin g the foll owing: `ca ll`, `summ arize` (ge ts names o f resource s returned ), `groupB yResourceT ype` (grou p by resou rce), `cre ateExtensi onObject`, and `crea teIdentifi erObject`. | |
509 | ||
510 | Additional FHIR pars ing can be done with the $tas. helpers.jm espath obj ect. See [ http://jme spath.org/ ](http://j mespath.or g/) for de tails on J MESPath qu ery langua ge. | |
511 | ||
512 | > You can find more $tas examp les in `./ tas/test`. | |
513 | ||
514 | ## Authori zation | |
515 | ||
516 | IAM handle s authenti cation, bu t authoriz ation is c ustom. Req uests cont ain the HT TP_ACCESSR OLES heade r with the format "R OLE1^ROLE2 ^ROLE3". T he TAS API handles t he interna l mechanic s of parsi ng these r oles. | |
517 | ||
518 | Operations can be lo cked down to group b y using th e Authoriz eCommand c ommand | |
519 | ||
520 | Example: | |
521 | ||
522 | comman ds | |
523 | .s tart('incr ement') | |
524 | .n ext(new Au thorizeCom mand('SBTE ST_ADMIN') ) | |
525 | .n ext(new In crementCom mand()) | |
526 | .e nd() | |
527 | ||
528 | To allow m ore than o ne group, use the ar ray form: | |
529 | ||
530 | comman ds | |
531 | .s tart('conc at') | |
532 | .n ext(new Au thorizeCom mand(['SBT EST_WRITER ', 'SBTEST _ADMIN'])) | |
533 | .n ext(new Co ncatComman d()) | |
534 | .e nd() | |
535 | ||
536 | ## Validat ion | |
537 | ||
538 | Validated is provide d with the validate. js library and expos ed via Val idateComma nd. | |
539 | ||
540 | See the fo llowing co mplete exa mple: | |
541 | ||
542 | //+ pr actical pi peline | |
543 | const validator = { | |
544 | re source: { presence: true, form at: { patt ern: "[a-z 0-9]+", fl ags: "i" } }, | |
545 | pa rams: { pr esence: tr ue } | |
546 | } | |
547 | comman ds | |
548 | .s tart('fhir -query', { descripti on: () => { return { summary: `Loads dat a from FHI R, extract s identifi ers.`, val idator } } }) | |
549 | .n ext(new Au thorizeCom mand(['SBT EST_WRITER ', 'SBTEST _ADMIN'])) | |
550 | .n ext(new Va lidateComm and(valida tor)) | |
551 | .n ext(new fh ir.FhirQue ryCommand( )) | |
552 | .n ext(new fh ir.FhirGro upByComman d()) | |
553 | .e nd() | |
554 | ||
555 | This examp le will ch eck author ization, v alidate, q uery FHIR, then grou p the data . If the i nput data is invalid , the Vali dateComman d will imm ediately s top proces sing and r eturn the result. | |
556 | ||
557 | ## Descrip tions | |
558 | ||
559 | You can vi ew what pu blicly acc essible co mmands are avilable on an endp oint names pace by ca lling the `_describe ` command. | |
560 | ||
561 | Example: | |
562 | ||
563 | http:// IP /api/sb/ex ample/modu lar/_descr ibe | |
564 | ||
565 | Snippet of output: | |
566 | ||
567 | [ | |
568 | { | |
569 | "name": "query", | |
570 | "descrip tion": { | |
571 | "sum mary": "Qu eries the example da ta.", | |
572 | "inp ut": { | |
573 | "start": " number", | |
574 | "size": "n umber" | |
575 | } | |
576 | } | |
577 | }, | |
578 | { | |
579 | "name": "amplify", | |
580 | "descrip tion": { | |
581 | "sum mary": "In crements n umber, the n multipli es by 10." , | |
582 | "inp ut": { | |
583 | "number": "number" | |
584 | } | |
585 | } | |
586 | }, | |
587 | .. . | |
588 | ] | |
589 | ||
590 | You set th is in the descriptio n function in a comm and: | |
591 | ||
592 | class extends $t as.command .Command { | |
593 | de scription( ) { | |
594 | return { | |
595 | summ ary: `Adds 1.`, | |
596 | inpu t: { | |
597 | number: "n umber", | |
598 | } | |
599 | } | |
600 | } | |
601 | as ync run(se curityCont ext, value s, adapter ) { | |
602 | return a dapter.cre ateRespons e($tas.con stants.sta tus.SUCCES S, { numbe r: parseIn t(values.n umber) + 1 }) | |
603 | } | |
604 | } | |
605 | ||
606 | Pipelines create a n ew command . Therefor e when usi ng the Aut horizeComm and comman d, you los e your des cription. You can co py a comma nd's descr iption to the pipeli ne with `$ tas.comman d.Registry ::copyDesc ription(CO MMAND_NAME )`. | |
607 | ||
608 | Example: | |
609 | ||
610 | comman ds | |
611 | .s tart('incr ement', { descriptio n: command s.copyDesc ription(In crementCom mand) }) | |
612 | .n ext(new Au thorizeCom mand('SBTE ST_ADMIN') ) | |
613 | .n ext(new In crementCom mand()) | |
614 | .e nd() | |
615 | ||
616 | ## Data | |
617 | ||
618 | ### Data P roviders | |
619 | ||
620 | Drivers fo r database s are gene rally writ ten by the organizat ion that b uild the d atabase. T hese entir ely abstra ct the det ails of th e the data base. You never work directly with the T abular Dat a Stream f ormat for SQL Server , the wire protocol for MongoD B, or ODat a with Azu re Table S torage. Th ese mechan ics are en tirely abs tracted. T here's no point in d iscussing them. You program ag ainst the driver, no t the prot ocol. | |
621 | ||
622 | In the TAS API, data providers abstract the driver s. These p roviders h elp to abs tract data base conne ctivity in cluding al l connecti on managem ent. conne ction stri ngs, user names, and passwords . | |
623 | ||
624 | Here are s ome exampl e data pro viders: | |
625 | ||
626 | * AMQP (sp ecial prov ider, see details la ter) | |
627 | ||
628 | * Azure | |
629 | ||
630 | * Elastics earch (v6) | |
631 | ||
632 | * Memory | |
633 | ||
634 | #### Data Binders | |
635 | ||
636 | When worki ng with bu siness log ic and com mands, you never pro gram direc tly agains t a provid er. The di fferences between da tabases ar e often so great, th at it's im practical to do so. | |
637 | ||
638 | Consider f or a momen t the diff erences be tween Azur e Table St orage, Mon goDB, and Elasticsea rch IDs wo rk differe ntly in ea ch of thes e database s. differe nces: Azur e Table St orage uses a Partiti onKey/RowK ey combina tion, Mong oDB uses a rich Obje ctID objec t, Elastic search use s a long s tring. The binder is where you smooth ou t the diff erences, s o you neve r have to deal with database I Ds in your business logic. You r binder w ould add t he special IDs on wr ite and re move them on read. | |
639 | ||
640 | Therefore, data bind ers provid e you with a decoupl ed way of interactin g with dat a provider s. | |
641 | ||
642 | > To summa rize: Driv ers abstra ct wire me chanics. P roviders a bstract dr ivers. Bin ders abstr act provid ers. | |
643 | ||
644 | The follow ing line w ill gain d ata access for `exam ple`: | |
645 | ||
646 | const example = $tas.provi ders.load( 'example') | |
647 | ||
648 | Here's an example of using `ex ample` dat a: | |
649 | ||
650 | await example.ge t(user_id, start, si ze, query) | |
651 | ||
652 | Notice tha t no data provider i s specifie d. This is set via e nvironment variables and contr olled by C M. | |
653 | ||
654 | There may be, howeve r, times w hen you ab solutely n eed a spec ific provi der. In th ese cases, you can s pecify tha t provider . This sho uld be ext remely rar e: | |
655 | ||
656 | const example = $tas.provi ders.load( 'example') ('azure) | |
657 | ||
658 | The defaul t provider is `memor y`. This i s a safe d efault for the sake of testing and easy of develop ment. | |
659 | ||
660 | > Do **NOT ** access a database directly in your co re-layer. This will break the ability to test with the in-me mory datab ase and ti e an API t ightly to one single database implementa tion. Alwa ys use a d ata binder . | |
661 | ||
662 | ||
663 | You must c reate a da ta binder for each d ata provid er you wan t to suppo rt. Your b inder will call the provider. The bindin g will be aware of t he specifi cs of the data provi der and wi ll be some what aware of your b usiness do main. It's a hybrid position. | |
664 | ||
665 | > Because your binde r is aware of the pr ovider, it can use a nything in the provi der, inclu ding the u nderlying provider d river. Thi s means th at if you need more advanced f unctionali ty, you ca n use prov ider funct ionality d irectly in your bind er. For ex ample, if you wanted to use th e MongoDB aggregate pipeline, you would do this in the binde r. | |
666 | ||
667 | An API's d ata-provid er is conf igured via the TAS_P ROVIDERS e nvironment variable with a for mat simila r to this example: | |
668 | ||
669 | TAS_PR OVIDERS=LO GGING:fs,M etabase:az ure,EXAMPL E:azure | |
670 | ||
671 | > The `mem ory` provi der is the default. | |
672 | ||
673 | Most provi ders will not activa te without the requi red enviro nment vari able. For example, ` TAS_AZURE_ STORAGE_NA ME` and `T AS_AZURE_S TORAGE_KEY ` are requ ired to ac tivate Azu re storage and `TAS_ MONGODB_CO NNECTION_S TRING` and `TAS_MONG ODB_DATABA SE` are re quired to activate M ongoDB sto rage. | |
674 | ||
675 | Once you h ave proven the mecha nics of yo ur memory binder, yo u can use your memor y binder f or all tes ts. It's s trongly re commended that, wher e possible (e.g. not using agg regates), that you w rite suppo rt for a m emory data provider first. Thi s will ena ble testin g without requiring database s etup. Give n working tests for a specific provider, there's n o need to retest a p rovider wh en testing higher-le vel functi onality. I n short: u se the mem ory provid er for tes ts. | |
676 | ||
677 | ## curl Ex amples | |
678 | ||
679 | Here you c reate two documents, then: que ry by size 1 (showin g only doc ument 4444 44444444), query by size 2 (sh owing both ), query b y size 1 a nd start 2 (showing only docum ent 333333 333333). | |
680 | ||
681 | HOST_BASE= http:// IP /api/core | |
682 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/cr eate -d '{ "type": 1 ,"data": " the quick brown fox" }' | |
683 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/cr eate -d '{ "type": 1 ,"data": " jumped ove r the lazy dog" }' | |
684 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/qu ery -d '{ "start": 1 , "size": 1 }' | doc ker run -i python py thon -m js on.tool | |
685 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/qu ery -d '{ "start": 1 , "size": 2 }' | doc ker run -i python py thon -m js on.tool | |
686 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/qu ery -d '{ "start": 2 , "size": 1 }' | doc ker run -i python py thon -m js on.tool | |
687 | curl - sXPOST -H "Content-T ype: appli cation/jso n" -H 'Coo kie: IAMSE SSION=ABCD EF' $HOST_ BASE/examp le/data/qu ery -d '{ "start": 1 , "size": 1, "query" : { "textS earch": "d og" } }' | docker ru n -i pytho n python - m json.too l | |
688 | ||
689 | > `python -m json.to ol` is use d to forma t. `docker run -i py thon pytho n -m json. tool` is u sed to avo id install ing Python . | |
690 | ||
691 | ## Structu ral Overvi ew of APIs with TAS API | |
692 | ||
693 | The intern al mechani cs of this project a re contain ed in the `tas/` pro ject. **Do not edit files in t his folder .** | |
694 | ||
695 | Product de velopment is done in the `app/ ` and `tes t/` folder s | |
696 | ||
697 | Review the following structure : | |
698 | ||
699 | app/ | |
700 | ex ample/bind ings/ | |
701 | azure.js | |
702 | memory.j s | |
703 | mongodb. js | |
704 | ex ample/name spaces/ | |
705 | data.js | |
706 | modular. js | |
707 | v1.js | |
708 | ex ample/core .js | |
709 | ex ample/endp oint.js | |
710 | co nfig.js | |
711 | en dpoints.js | |
712 | test/ | |
713 | ||
714 | `example/` represent s a comple te endpoin t. An endp oint is ef fectively its own ap plication. With this understan ding, the TAS API ca n be thoug ht of a as platform for a as a suite of products. | |
715 | ||
716 | #### `app/ ` | |
717 | ||
718 | This folde r will con tain all p roduct API developme nt. Each f older unde r `app/` i ndicates a separate endpoint. | |
719 | ||
720 | #### `app/ endpoints. js` | |
721 | ||
722 | This is wh ere each A PI is conn ected with the overa ll system. Example: | |
723 | ||
724 | const $tas = req uire('../t as')() | |
725 | const setup = $t as.setupEn dpoint | |
726 | ||
727 | module .exports.i nit = app => { | |
728 | se tup(app, " config") | |
729 | // + ...more endpoints | |
730 | } | |
731 | ||
732 | #### `api/ example/en dpoint.js` | |
733 | ||
734 | This file contains t he setup a nd exposur e of an en dpoint. An example w as shown e arlier. | |
735 | ||
736 | #### `api/ example/co re.js` | |
737 | ||
738 | This file contains d evelopment specific to product business logic. It is not HTT P or AMQP aware, nor is it tie d directly to any sp ecific dat abase. | |
739 | ||
740 | #### `api/ example/bi ndings/` | |
741 | ||
742 | This folde r contains bindings for variou s database providers . Not all data provi ders will be used. H owever, it 's encoura ged to use `memory` for unit t esting. Mo re details in a late r section. | |
743 | ||
744 | #### `api/ endpoints/ versions/` | |
745 | ||
746 | This folde r contains the actua l, version ed product service A PI HTTP lo gic. | |
747 | ||
748 | #### `test /` | |
749 | ||
750 | This folde r contains various t ests for p roduct ser vice APIs. | |
751 | ||
752 | > Some con figuration is requir ed to be e xternal to the appli cation, se t by envir onment var iables. Th ese can be access fr om `proces s.env` and set in `p roductConf ig.js`. | |
753 | ||
754 | ## Advance d Details | |
755 | ||
756 | ### Isolat ion | |
757 | ||
758 | Each API i s entirely isolated. Coding er rors (e.g. syntax er rors) in o ne API wil l not caus e another API to bre ak. | |
759 | ||
760 | ### Partic ular Activ ation | |
761 | ||
762 | By default all APIs are active . Set TAS_ ACTIVATE t o activate only part icular API s. | |
763 | ||
764 | This is us eful for t ransitioni ng an API to a a sin gle API ho sting mode l (e.g. mi croservice ). | |
765 | ||
766 | For exampl e, one dep loyment ma y only hav e logging, but anoth er may onl y have con fig. | |
767 | ||
768 | Example: ` TAS_ACTIVA TE=logging ,health,me trics` | |
769 | ||
770 | ## Unit Te sting | |
771 | ||
772 | Testing sh ould be do ne at each layer of your appli cation. Yo u should w rite tests for the s ake of pro ving code for your d ata provid ers, for y our core l ayer, and for endpoi nts. | |
773 | ||
774 | Review the `tas/test ` folder f or testing examples. | |
775 | ||
776 | Endpoint t ests use t he followi ng pattern : | |
777 | ||
778 | "use s trict" | |
779 | ||
780 | const $tas = req uire('../' )() | |
781 | const { app, cha i } = $tas .chaiTest( ) | |
782 | const expect = c hai.expect | |
783 | const assert = c hai.assert | |
784 | ||
785 | const nconfig = $tas.confi g | |
786 | const idgen = $t as.helpers .idgen | |
787 | ||
788 | descri be("PUT /a pi/sbtest" , () => { | |
789 | be fore(() => { | |
790 | app.star t() | |
791 | }) | |
792 | af ter(() => { | |
793 | app.stop () | |
794 | }) | |
795 | ||
796 | it ("puts and get entit y entity", async fun ction () { | |
797 | const us er_id = id gen.genera te('user_i d' + this. test.title ) | |
798 | const id = idgen.g enerate(th is.test.ti tle) | |
799 | ||
800 | let res = await ch ai.request (app.baseA ddress()) | |
801 | .put ('/api/v2/ sbtest/' + id) | |
802 | .set ('Cookie', 'IAMSESSI ON=' + thi s.test.tit le) | |
803 | .sen d({ | |
804 | type: 'war ning', | |
805 | level: 'in fo', | |
806 | data: 'thi s is an er ror messag e' | |
807 | }) | |
808 | expect(r es).to.hav e.status(2 04) | |
809 | ||
810 | res = aw ait chai.r equest(app .baseAddre ss()) | |
811 | .get ('/api/v2/ sbtest/' + id) | |
812 | .set ('Authoriz ation', 'B earer ' + user_id) | |
813 | const re sults = re s.body | |
814 | expect(r esults.ite m.type).to .eq('warni ng') | |
815 | }) | |
816 | }) | |
817 | ||
818 | Before tes ts, the ap p is start ed: | |
819 | ||
820 | app.st art() | |
821 | ||
822 | After test s, the app is stoppe d: | |
823 | ||
824 | app.st op() | |
825 | ||
826 | To ensure your tests call the correct ad dress, be sure to us e `app.bas eAddress() `: | |
827 | ||
828 | chai.r equest(app .baseAddre ss()) | |
829 | ||
830 | To link yo ur tests t ogether, g enerate an ID and us e it as yo ur authori zation tok en: | |
831 | ||
832 | const user_id = idgen.gene rate('0') | |
833 | ||
834 | ... | |
835 | ||
836 | .set(' Authorizat ion', 'Bea rer ' + us er_id) | |
837 | ||
838 | Review `ta s/test/end point-*-.j s` tests f or more co mplex exam ples. | |
839 | ||
840 | ## Adding an Endpoin t | |
841 | ||
842 | To create a new endp oint: | |
843 | ||
844 | 1) Copy th e `./tas/a pp/templat e` folder to the `./ app` folde r | |
845 | 2) Rename | |
846 | 3) Registe r to `./ap p/endpoint s.js` via the `setup ` function (e.g. `se tup(app, ' logging')` ). | |
847 | ||
848 | ## Program ming Langu ages and F ormats | |
849 | ||
850 | The API fo undation i s built on Node.js 8 using the programmi ng languag e ES6 (aka ES2015). | |
851 | ||
852 | ES6, like ES5 JavaSc ript, and TypeScript separates lined wit h new line s (and cod e on the s ame line w ith semico lon). Beca use lines are alread y separate d by new l ines, semi colons are not used to separat e lines. T his is an artifact o f C/C++/C# and clutt ers ES6/Ty peScript c ode. Avoid semicolon s where po ssible. | |
853 | ||
854 | ES6 has ri ch functio nal progra mming feat ures that ES5 lacks, like map/ reduce/fil ter/find, therefore 3rd party functional libraries like unde rscore and lodash ar e largely unneeded. See [http: //es6-feat ures.org]( http://es6 -features. org) and [ https://no de.green]( https://no de.green) for more d etails. | |
855 | ||
856 | Files use LF, not CR LF. Keep a n empty li ne at the end of eac h file. | |
857 | ||
858 | ## Databas e Setup | |
859 | ||
860 | Elasticsea rch, memor y, file-sy stem, and Azure Tabl e Storage do not req uire any a dditional setup. | |
861 | ||
862 | ## Databas e Connecti vity | |
863 | ||
864 | To example database connectivi ty, you mu st send th e applicat ion a conn ection str ing via en vironment variable. | |
865 | ||
866 | This is se t in your `docker-co mpose.yml` file or w ith the Do cker `-e` commandlin e argument . | |
867 | ||
868 | See the be ginning of this docu ment for d etails. | |
869 | ||
870 | ## Authent ication fo r Developm ent | |
871 | ||
872 | To emulate authentic ation, use the stand ard `Cooki e` header and specif y a value for IAMSES SION: | |
873 | ||
874 | curl - H 'Cookie: IAMSESSIO N=ABCDEFG' http://12 7.0.0.1:30 00/api/cor e/logging/ v2 | |
875 | ||
876 | Authorizat ion is pro vided with the ACCES SROLES hea der | |
877 | ||
878 | curl - H 'Cookie: IAMSESSIO N=ABCDEFG' -H "ACCES SROLES: SB TEST_ADMIN " http://1 27.0.0.1:3 000/api/co re/logging /v2 | |
879 | ||
880 | In the ful l Docker d eveloper e nvironment , fuller a uthenticat ion emulat ion is pro vided auto matically. | |
881 | ||
882 | ## Usage E xamples | |
883 | ||
884 | **GET** | |
885 | ||
886 | curl - H 'Cookie: IAMSESSIO N=ABCDEFG' http://12 7.0.0.1:30 00/api/log ging/v2 | |
887 | ||
888 | **POST** | |
889 | ||
890 | curl - XPOST -H " Content-Ty pe: applic ation/json " -H 'Cook ie: IAMSES SION=ABCDE FG' http:/ /127.0.0.1 :3000/api/ logging/v2 -d '{"typ e":1,"data ":2}' |
Araxis Merge (but not the data content of this report) is Copyright © 1993-2016 Araxis Ltd (www.araxis.com). All rights reserved.