-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtrack.yml
More file actions
736 lines (671 loc) · 25.7 KB
/
track.yml
File metadata and controls
736 lines (671 loc) · 25.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
slug: full-stack-tutorial
id: s0ynild6wctq
type: track
title: Full Stack Tutorial
teaser: Build the IT infrastructure for a company that roasts and sells delicious,
freshly roasted coffee. You’ll learn how the InterSystems IRIS data platform can
serve as the backbone of your IT architecture.
description: |-
This tutorial is divided into three parts:
- **Part 1:** create database tables and write raw coffee bean deliveries to the database.
- **Part 2:** build web services that power the roasting operations and online store.
- **Part 3:** build a web storefront in Vue.js

icon: https://cdn.instruqt.com/assets/intersystems/vscode.png
tags:
- iris
- intersystems
- fullstack
owner: intersystems
developers:
- ade@instruqt.com
- dmitry@caretdev.com
- nikolay.solovyev@caretdev.com
- raj.singh@intersystems.com
private: true
published: false
challenges:
- slug: 01-create-db
id: rc49n14ohxmg
type: challenge
title: Databases and SQL
teaser: Database creation with raw SQL
assignment: |-
Copy and Paste the following SQL CREATE statement in the SQL "Execute Query" box on the left (below the "Execute" button) to create the <code>ICO.inventory</code> table.
Then press the "Execute" button to run the query.
```SQL
CREATE TABLE ICO.inventory
(
vendor_id VARCHAR(128),
vendor_product_code VARCHAR(128),
quantity_kg DECIMAL(10,2),
date_arrival DATE
)
```
Delete that statement, then copy and paste the following to create the <code>ICO.catalog table</code>.
Press the "Execute" button to run the query.
```SQL
CREATE TABLE ICO.catalog
(
catalog_id BIGINT IDENTITY,
product_code VARCHAR(128),
quantity INTEGER,
price DECIMAL(10,2),
time_roasted DATETIME,
roasting_notes VARCHAR(2048),
img VARCHAR(2048)
)
```
notes:
- type: image
url: https://dev-start.intersystems.com/wp-content/uploads/2021/03/IrisCoffee-Sketch-part-1-233x300.png
- type: text
contents: |-
IRIS Coffee Company has three major divisions in the company:
- the **warehouse** stores the raw coffee bean inventory. Its data will be in the table <code>ICO.inventory</code>
- the **roastery** roasts the beans, and doesn’t need to store data
- the **storefront**, where the company sells the roasted coffee. Its data will be in the table <code>ICO.catalog</code>
Use the SQL client built into the InterSystems IRIS Terminal to create those two tables using <code>SQL CREATE</code> statements.
tabs:
- title: IRIS
type: service
hostname: iris
path: /csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER&IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
difficulty: basic
timelimit: 900
- slug: 02-python-data-loading
id: 101uev0fgbmq
type: challenge
title: Python data loading
teaser: Use SQL in a Python script for more flexibility
assignment: |-
## Run the inventory import script
In the terminal on the left, run the following commands.
Setup odbc driver
```
sudo odbcinst -i -d -f pyodbc_wheel/odbcinst.ini
```
Execute python script
```
python3 manifest_importer.py
```
## Python script walkthrough
In you are interested in the details of how the script works, click on the VSCode tab and follow along. The <code>manifest_importer.py</code> file should be open for you.
Notice some of the key elements of this script. In the main function definition, we simply import the JSON order manifest file and validate it, checking for the structure needed for the inventory database.
```python
def main():
with open('./order_manifest.json') as f:
data = json.load(f)
data, status, exp = validate_manifest(data)
```
The next thing we do in main() is read database credentials from the file, <code>connection.config</code>.
```python
connection_detail = get_connection_info("connection.config")
ip = connection_detail["ip"]
port = int(connection_detail["port"])
namespace = connection_detail["namespace"]
username = connection_detail["username"]
password = connection_detail["password"]
driver = "{InterSystems ODBC}"
```
Then we set up a connection to the database using an ODBC driver.
```python
connection_string = 'DRIVER={};SERVER={};PORT={};DATABASE={};UID={};PWD={}' \
.format(driver, ip, port, namespace, username, password)
connection = pyodbc.connect(connection_string)
```
If all goes well, we call load_manifest with the JSON data and the database connection object.
```python
msg = load_manifest(data, connection)
```
In load_manifest, we iterate through all the items in the JSON file, inserting each one into the ICO.inventory table we created previously using SQL INSERT statements. Here’s how that works: First, we define our base SQL INSERT statement:
```python
fieldnamesql = "INSERT INTO ICO.inventory (vendor_id, vendor_product_code, quantity_kg, date_arrival)"
```
On the next two lines, we create a new date string based on the current date, for example, ‘2020-06-18’. This will be the date the product arrived in the warehouse.
```python
today = date.today()
mydate = today.strftime("%Y-%m-%d")
```
Now, the code loops through each item object in the JSON file, and uses the data there to construct the VALUES part of our SQL INSERT statement. The result is a completed SQL INSERT statement that looks something like this:
```sql
INSERT INTO ICO.inventory (vendor_id, vendor_product_code, quantity_kg, date_arrival) VALUES (ETRADER, ETHIOPIA32, 200, ‘2020-06-18’)
```
Now the code runs the completed SQL statement. We defined our database cursor on the first line of the function, so now we can run execute on the cursor with the SQL statement as its input.
```python
cursor.execute(valsql)
```
notes:
- type: text
contents: |-
In this challenge, we will populate the database with raw coffee bean orders, simulating shipments of raw beans from vendors around the world. Assume that all the shipments are consolidated in a single order manifest in JSON format.
To load the data, we’ll use a Python program to parse the order manifest file and insert the deliveries into the database, also using SQL, but this time within Python.
tabs:
- title: Terminal
type: terminal
hostname: vscode
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/setup
port: 8080
difficulty: basic
timelimit: 900
- slug: 03-sql-queries
id: iuhf83icltd0
type: challenge
title: SQL database queries
teaser: Let’s make sure the data was inserted
assignment: |-
Execute SQL Query
```
select * from ICO.inventory
```
You should see five rows of raw coffee beans in inventory.
Try a couple queries to play with our inventory in more detail. See all large deliveries — over 100 kilograms. You might want to start roasting these first.
```SQL
SELECT * FROM ICO.inventory WHERE quantity_kg > 100
```
Or you may need to see all inventory from a particular vendor.
```SQL
SELECT * FROM ICO.inventory WHERE vendor_id LIKE 'DKE'
```
notes:
- type: text
contents: Let’s check out what we now have in inventory with some SQL queries!
tabs:
- title: IRIS
type: service
hostname: iris
path: /csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER&IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
difficulty: basic
timelimit: 900
- slug: 04-add-new-inventory
id: o9crvqeawauj
type: challenge
title: Add your own inventory
teaser: Finally, add more inventory on your own.
assignment: |-
Edit `order_manifest.json` file in the IDE.
Change the values as you like.
Run python `manifest_importer.py` again.
```
python manifest_importer.py
```
notes:
- type: text
contents: Finally, add more inventory on your own.
tabs:
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/setup
port: 8080
- title: Terminal
type: terminal
hostname: vscode
difficulty: basic
timelimit: 900
- slug: quiz-sql
id: o8llslesr7gu
type: quiz
title: 'Learning check: IRIS and SQL'
teaser: Test your knowledge about using SQL with InterSystems IRIS
assignment: With which common languages can you use InterSystems IRIS and SQL?
answers:
- Python
- Java
- Node.js
- C#/.NET
solution:
- 0
- 1
- 2
- 3
difficulty: basic
timelimit: 500
- slug: 05-os-db-query
id: cs0hpvve8izh
type: challenge
title: ObjectScript database query
teaser: Edit an object with ObjectScript
assignment: |-
Open IRIS Terminal
Type the following commands to get the ICO.inventory record having a primary key of 1.
Fetches record 1 from the database
```
set item = ##class(ICO.inventory).%OpenId(1)
```
Prints the record’s data to the screen
```
zwrite item
```
Changes a property’s value
```
set item.quantitykg = 300
```
Prints again to verify the change
```
zwrite item
```
Writes changed data to the database
```
do item.%Save()
```
notes:
- type: text
contents: |-
A well-designed system never allows business applications to operate
directly on the database. Instead, we provide access via services so that we
can control and monitor the actions taken.
In the next steps, we build out
the suite of RESTful web services needed for the business to function.
- type: text
contents: |-
With most databases, you have no choice but to use a middleware framework — for example, Java Spring, Python Flask, or Node.js Express, — and talk to the data layer via SQL. You can certainly do that with InterSystems IRIS as well, but you also have another easier and higher performance option:
* Code in ObjectScript: Get the performance of stored procedures, and the flexibility, power and ease-of-use of a real programming language.
* No middleware required: The web server and middleware layer are built-in!
- type: text
contents: Now let’s see how easy it is with ObjectScript, especially when you
want to get a record using its primary key.
tabs:
- title: IRIS Terminal
type: terminal
hostname: iris
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/setup
port: 8080
- title: IRIS
type: service
hostname: iris
path: /csp/sys/exp/%25CSP.UI.Portal.SQL.Home.zen?$NAMESPACE=USER&IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: Terminal
type: terminal
hostname: vscode
difficulty: basic
timelimit: 500
- slug: 06-db-query
id: yl5kgs1or3ul
type: challenge
title: Database query with ObjectScript and SQL
teaser: Database query with ObjectScript and SQL
assignment: |-
Type in IRIS Terminal:
Sets a variable with a valid SQL SELECT statement
```
set sqlquery = "SELECT * FROM ICO.inventory ORDER BY vendor_id"
```
Executes the SELECT and stores a pointer to results in `rs`
```
set rs = ##class(%SQL.Statement).%ExecDirect(,sqlquery)
```
Iterates over `rs`, printing the `vendor_id` property
```
while rs.%Next() { Write !, rs.%Get("vendor_id") }
```
notes:
- type: text
contents: |-
Let’s perform a more complex query using SQL right in your ObjectScript code.
Continue using IRIS Terminal
tabs:
- title: IRIS Terminal
type: terminal
hostname: iris
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
- title: IRIS
type: service
hostname: iris
path: /csp/sys/UtilHome.csp?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: Terminal
type: terminal
hostname: vscode
difficulty: basic
timelimit: 500
- slug: 07-os-classes
id: txkl7pug7nsz
type: challenge
title: ObjectScript Classes
teaser: Writing ObjectScript Classes
assignment: |-
* Expand src, then ICO.
* Right-click on the ICO folder and select “New File”.
* Name it `Test.cls`.
* In that file, type:
```
Class ICO.Test
{
ClassMethod QueryDB() As %Status
{
set sqlquery = "SELECT * FROM ICO.inventory"
set rs = ##class(%SQL.Statement).%ExecDirect(,sqlquery)
while rs.%Next() {
Write !, rs.%Get("vendor_id")
}
}
}
```
* Save the file
* Run this method in IRIS Terminal
```
do ##class(ICO.Test).QueryDB()
```
notes:
- type: text
contents: |-
That wasn’t very pretty because we put a lot of code on a single line.
Now let’s put our ObjectScript code in a file.
tabs:
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
- title: IRIS Terminal
type: terminal
hostname: iris
difficulty: basic
timelimit: 500
- slug: 08-build-web-services
id: 5shnvzylcwk2
type: challenge
title: Build Web Services
teaser: Build Web Services
assignment: |-
We need to make a few changes to the ObjectScript code thatrepresents
our database tables so that we can also output the data as JSON.
But first let’s look at the code already in the database.
* In the VSCode, click on the InterSystems icon to view the ObjectScript Explorer.
This shows you the code that’s been loaded and compiled on the database server, rather than the local version of code you work on.
* Expand the folders `Classes` and `ICO` and you see two files with familiar names, `catalog` and `inventory` (with .cls extensions).
When we created database tables in part 1 using SQL statements, companion ObjectScript classes were also created at the same time.
* Click on `catalog.cls`. Note that columns are called Properties, but the data type and range restrictions should look familiar.
Also look at `inventory.cls`
* Close any files you have opened.
### JSON-enable the Data Tables
We need to change these classes slightly to enable JSON output, and make that output look nice, so let’s do that now.
* Go back to the normal file explorer by clicking the documents icon Theia documents icon.
* Copy `catalog.cls` and `inventory.cls` from `src_Sample/ICO` folder to `src/ICO`
* Open and save both files, and choose the “Overwrite server” option.
This uploads and compiles your new versions of these classes with the addition of %JSON.Adapter and %JSONFIELDNAME.
We did 2 things in these files:
* Extend `%JSON.Adapter` to enable automatic JSON output of this table’s data.
* Add `%JSONFIELDNAME` “property parameters” to selected Properties, to change its name when used in JSON output.
notes:
- type: text
contents: |-
That was a gentle introduction to ObjectScript.
Now let’s use what you’ve learned to build the web services needed to power our coffee roasting business. We will:
* Copy and compile pre-written code to the database
* JSON-enable the database tables
* Examine how each RESTful API is built
* Deploy and test the web services using curl and the browser
* Use a web service to move coffee from inventory to the store
* Record sales
- type: text
contents: |-
In part 1 we created database tables using standard SQL.
What we didn’t mention is that behind the scenes, corresponding ObjectScript classes were created as well!
This lets developers easily switch between SQL and code depending on which style makes sense for the task at hand.

tabs:
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
- title: IRIS
type: service
hostname: iris
path: /csp/sys/UtilHome.csp?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: IRIS Terminal
type: terminal
hostname: iris
difficulty: basic
timelimit: 500
- slug: 09-restful-service
id: nybykbczjwwh
type: challenge
title: Your first RESTful Service
teaser: Build RESTful Services
assignment: |-
With the basic JSON support set up, we can build a service.
* Copy file `Handler.cls` from `src_Sample/ICO` folder to `src/ICO`
* Open and save the file (this time you won’t need the “Overwrite server” option because this class is new).
Now that we’ve written the middleware REST APIs, the final step in making the services work is to expose them to the web.
InterSystems IRIS provides a tool to route web requests to ObjectScript code in much the same way as Node.js Express or Python Flask.
Let’s use the Management Portal to hook this IRIS class into the web.
* Click the *Create New Web Application* button.
* Under *Name*, enter `/api/coffeeco` (the base endpoint).
* Under *Namespace*, select *USER*.
* Make sure *Enable Application* is checked.
* Under *Enable*, select *REST*.
* For the *Dispatch Class*, type `ICO.Handler` (the IRIS Class all URLs starting with `/api/coffeeco` will be dispatched to).
* Under *Security Settings*, check *Unauthenticated* and *Password* for *Allowed Authentication Methods*.
* Click *Save* next to the title Edit Web Application.
Now you will see new tabs, one of which is *Application Roles*.
Click that tab, then *%All* under the *Available* list, then click the right arrow to copy it to the *Selected* list. Click *Assign*.
notes:
- type: text
contents: ''
- type: text
contents: ''
- type: text
contents: ''
tabs:
- title: IRIS
type: service
hostname: iris
path: /csp/sys/sec/%25CSP.UI.Portal.Applications.WebList.zen?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
difficulty: basic
timelimit: 500
- slug: 10-roast-coffee-beans
id: wvrajhott0ux
type: challenge
title: Roast coffee beans
teaser: A short description of the challenge.
assignment: |-
In Handler.cls, look at the <Routes> XData section at the end of the file.
See that the Url path `/inventory/getbeans/:id/:quantity` calls the ClassMethod GetRawBeans.
Notice the URL substitution technique to pass values in the URL.
Find the *GetRawBeans* ClassMethod in the file. Since we know the primary key of the bean record (it was passed as the `:id` in the URL),
we can use ObjectScript’s easy way to query the database with the *%OpenId()*. The rest of the method:
* Checks that enough quantity exists
* Decrements the quantity requested from inventory
* Returns the new inventory quantity to the requestor
Let’s run an actual request to get beans out of inventory for roasting.
This request can’t be tested by pasting the URL into a browser because you can’t send POST requests that way, so let’s use curl.
In the VSCode’s terminal, type:
```
curl -X POST http://iris:52773/api/coffeeco/inventory/getbeans/1/2.4
```
To get prettier output, pipe the response through [jq](https://stedolan.github.io/jq/):
```
curl -X POST http://iris:52773/api/coffeeco/inventory/getbeans/1/2.4 | jq
```
notes:
- type: text
contents: |-
Now that you can get a response from a simple URL request, we know the services are working.
Let’s operate the coffee business now. First up is simulating taking raw coffee beans out of inventory and roasting them.
We’ll use the `/api/coffeeco/inventory/getbeans` API to do this.
tabs:
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
- title: Terminal
type: terminal
hostname: vscode
- title: IRIS
type: service
hostname: iris
path: /csp/sys/UtilHome.csp?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: IRIS Terminal
type: terminal
hostname: iris
difficulty: basic
timelimit: 300
- slug: 11-put-coffee-in-the-store
id: qnoswekskxvk
type: challenge
title: Put coffee in the store
teaser: A short description of the challenge.
assignment: |-
In this simple example, the quantity requested doesn’t get recorded anywhere.
We will count on the application making the request to take care of roasting coffee, bagging it and putting it in the store for sale.
Let’s do that now. In the services/samples directory, you’ll find 2 scripts:
* createproducts.sh: Creates 5 sample coffee products ready for sale.The first 3 were roasted today,
and the last 2 were roasted 6 days ago. This gives us some relatively stale inventory to discount in the store.
* loadproducts.sh: Runs a curl command that iterates through every JSON file in the directory and uses the web
service you just wrote to load the data into ICO.catalog.
In the terminal, type
```
cd /opt/intersystems/src/services/samples
sh createproducts.sh
sh loadproducts.sh
```
If you’re not comfortable running a script you didn’t write yourself (which is smart from a security perspective),
you can manually run your own curl commands to load the data. Here’s an example:
```
curl -X POST -d "@product_brazil_dark.json" \
-H "Content-Type: application/json" \
http://iris:52773/api/coffeeco/catalog/catalogproduct
```
notes:
- type: text
contents: |-
In this simple example, the quantity requested doesn’t get recorded anywhere.
We will count on the application making the request to take care of roasting coffee, bagging it and putting it in the store for sale.
tabs:
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/services
port: 8080
- title: Terminal
type: terminal
hostname: vscode
- title: IRIS
type: service
hostname: iris
path: /csp/sys/UtilHome.csp?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
- title: IRIS Terminal
type: terminal
hostname: iris
difficulty: basic
timelimit: 300
- slug: 12-make-a-sale
id: upshsecwfgt4
type: challenge
title: Make a sale
teaser: A short description of the challenge.
assignment: |-
### Try out the services
Query for fresh products:
```
curl http://iris:52773/api/coffeeco/catalog/getproducts | jq
```
Query for stale:
```
curl http://iris:52773/api/coffeeco/catalog/getproducts/0 | jq
```
Try selling products:
```
curl -X POST http://iris:52773/api/coffeeco/catalog/sellproduct/1/2 | jq
```
The response should look similar to this.
```
{
"catalog_id": 1,
"product_code": "BRAZILDARK",
"quantity": 38,
"price": 13.99,
"time_roasted": "2021-02-03T09:00:00Z",
"roasting_notes": "Full bodied and low acidity. Thick, creamy, nutty and semi-sweet.",
"img": "brazil_dark.jpg"
}
```
notes:
- type: text
contents: |-
Our final service records coffee sales, SellProduct.It takes as input the product ID and the quantity of bags being sold.
This is extremely simplified, as we won’t do any error checking or special payment handling or shipping.
We’ll just decrement the catalog’s quantity of coffee bags, assuming everything else is taken care of on the front end.
We also will assume if the customer bought multiple products, the client will send a SellProduct request for each.
Just like we did in the GetRawBeans method, we’ll take advantage of ObjectScript’s convenience methods for querying records
when you know their ID: %ExistsId, %OpenId, and %Save. Since this method is so similar to GetRawBeans, there’s nothing new to explain.
tabs:
- title: Terminal
type: terminal
hostname: vscode
difficulty: basic
timelimit: 300
- slug: 13-view-the-storefront
id: hi3loykke6n7
type: challenge
title: Customize the code
teaser: A short description of the challenge.
assignment: |-
The code has all been written for you, so let’s run it and see how it works.
First, let’s start installing some required packages.
That will take a few minutes, and we can make some edits those download.
In the VSCode’s terminal, enter the following commands.
```
yarn install
```
Now let’s run the app in a built-in development web server.
* Enter the following command:
```
yarn serve
```
* Switch to tab *IRIS Coffee Company*
You should see a list of products for sale.
notes:
- type: text
contents: |-
In part 3 of the tutorial, you will see the online storefront for your coffee operation.
It uses the Vue.js JavaScript framework to create a single-page web app (SPA).
Teaching Vue.js is beyond the scope of this tutorial, but you get a flavor for how it was built,
and see how the REST services you created in Part 2 are used by this app.
tabs:
- title: Terminal
type: terminal
hostname: vscode
- title: IRIS Coffee Company
type: service
hostname: vscode
port: 4200
- title: VSCode
type: service
hostname: vscode
path: /?folder=/opt/intersystems/src/frontend
port: 8080
- title: IRIS
type: service
hostname: iris
path: /csp/sys/UtilHome.csp?IRISUsername=_SYSTEM&IRISPassword=SYS
port: 52773
difficulty: basic
timelimit: 300
checksum: "9949671212647182669"