In this article, I make a simple REST API for tracking products using IOTA. This Tracking API will be used by products owner to record their products and all data they need about it(location, owner, modifications, time) then the API will push data to tangle than the API will respond with the root address to track all products and array of addresses for each product. This array of addresses should be printed as QR code on each product for QR-code reader to update/read data. For the tangled part, I used MAM restricted for communication and generate rout and addresses using it. You can found what I do in detail here.

The Sequence Diagram of the REST API:

API endpoints, Calls, controller and response

Creating Products Post Call

The client needs to send all his products information like id, date, details…etc on JSON array:

{[

{

id:”15p6013”,

date:”1/11/2019”,

location:”Cairo”

},

{

id:”20p6013”,

date:”1/11/2019”, location:”Cairo” }, ...... ]}

It will look like this on Postman

route:

app.route(‘/createproducts’)

.post(tracker.create_products)

Controller:

const initComm = require(‘./iota_comm_modules/initComm’)

exports.create_products = (req, res) => { initComm.execute(req.body.products).then(function(tracker) { res.json(tracker) })}

The IOTA module. all IOTA modules are included form this article.

const init = (_products)=>{ SendMamRestricted.execute("initialize root").then(function(result) { trackedProducts['rootAddress'] = result SendPublicTransaction.execute(IotaGlobal.seed,IotaGlobal.address,result) }) return PublishAll.execute(_products) } const initComm = async(_products) =>{ trackedProducts['addresses'] = await init(_products) return trackedProducts }

Then the response will be a JSON object with the root address on MAM Merkel tree, Could be used in GET call to fetch all product data and Array of addresses for each product.

Response:

{ "rootAddress": "NEH9MERQJWOYERNDMQJLESEUSIUMBAZ9DTFCNRVUVOGNWDNDFGERMTOTXUWICFYRJYUFRFDVMVXJTIEPG", "addresses": [ "BJKXGMJLMJFXUVZNL9FJZDIESOFQZIHCEUELPFZSUYYFKYVQGSSQNONWZEKTKUIPSWVJFAZOBRQZQJVUL", "FMA9BONNEWBLBXLCJ9DVCFSHDSXAWDKYUTRV9DVSY99TVRCWQ9HZ9NWDIUDBWXHCTNAAZOEVYTK9TWZLP" ] }

Now using all these addresses you can get data by ‘GET’ call.

Get Products Info GET Call

The client sends the address of a group of products he wants to keep track of.

endpoint

http://localhost:5200/getproducts?address=YLMBOYMLPTUFDESSIPJORHEMTVKCWRCZBYZBSDFVDPLEXPCZNHFOTFCZFJNUYYZMUDMJZNSPCUPLHBYNQ

//first product address should return his data and data for all products after it. //first product address should return his data and data for all products after it.

route

app.route(‘/getproducts’) .get(tracker.get_products);

Controller

const fetchMamRestricted= require(‘./iota_comm_modules/FetchMamRestricted’) exports.get_products = async (req,res) =>{ const productsData = await fetchMamRestricted.execute(req.query.address) fetchMamRestricted.cleanResp() res.json(productsData) }

IOTA Module

let resp = [] const logData = data => { resp.push(IotaGlobal.converter.trytesToAscii(data)) } const FetchMam = async (_root) => { // Callback used to pass data + returns next_root await IotaGlobal.Mam.fetch(_root, mamType, mamSecret, logData) return resp } const cleanResp = ()=>{ resp = [] }

Response products info and all new products added or changes happened after that:

[ "{ "id": "15P6013","time":"2272019","location":"Cairo"}", "{"id":"15P66666","time":"06071997","location":"Egypt"}" ]

Update Call

This call will be made by the IoT devices assume some products transferred to another country or got some modification whatever.

I used post call as I can’t update data already deployed on Tangle

endpoint:

Body(body could be any form of data the user want to send):

{ id: ‘15p6013’, time: ‘noew now’, owner: ‘john’, details: ‘lorem lorem lorem’ }

route:

app.route(‘/updateproduct’) .post(tracker.update_product)

controller:

const sendMamRestricted = require(‘./iota_comm_modules/SendMamRestricted’) exports.update_product = (req, res) => { console.log(req.body.data) sendMamRestricted.execute(JSON.stringify(req.body.data)).then(function(tracker) {res.json(tracker)})}

IOTA Module:

const Publish = async data => { // Convert the JSON to trytes and create a MAM message const trytes = IotaGlobal.converter.asciiToTrytes(data) const message = IotaGlobal.Mam.create(mamState, trytes) // Update the MAM state to the state of this latest message mamState = message.state // Attach the message await IotaGlobal.Mam.attach(message.payload, message.address, 3, 9) return message.root }

Response:

“SVGLNSIUTKYDIPJQJQGFJDKGZAQIQ9BTCQJXLAUZFRDKQLOJPMLNBBIXZWBBFUPWXJFQZCODZYTKEFL9V”

It’s the new address has been generated client could user could get it from previous addresses he has.

Test it using GET call

http://localhost:5200/getproducts?address=SVGLNSIUTKYDIPJQJQGFJDKGZAQIQ9BTCQJXLAUZFRDKQLOJPMLNBBIXZWBBFUPWXJFQZCODZYTKEFL9V //same address returned from update call

And it will give response:

[ “{”id”:”15p6013”,”time”:”noew now”,”owner”:”john”,”details”:”lorem lorem lorem”}” ]

To make sure everything works as expected. I will use the GET call with the root address and see if the update has been added to the Merkel tree or not.

Endpoint:

Response:

[ “initialize root”, “{\”id\”:\”15P6013\”,\”time\”:\”2272019\”,\”location\”:\”Cairo\”}”, “{\”id\”:\”15P66666\”,\”time\”:\”06071997\”,\”location\”:\”Yarab\”}”, “{\”id\”:\”15p6013\”,\”time\”:\”noew now\”,\”owner\”:\”john\”,\”details\”:\”lorem lorem lorem\”}” ]

The updates pushed by the IoT devices had been added!

What to do next?

1-Need to get user public address on POST calls to be more personalized for each user.

2-Need to send MAM restricted password when products had been created then add this password to IOT devices for updates.

But all these updates are simple and I didn’t add them to focus on the main problem.

Practically, All the API calls will return some unorganized data so I could add a filter module by time. As the Merkel tree changed by time ex:

address1→ for all changes from 20/1/2019 till now.

address2→ for all changes from 30/11/2019 till now.

……

After the time filter, I need to add ID filters to get all changes happened to a specific product or range of products. To be more organized and help the developer with no experience in tangle interact with it. It would be awesome if I found a way to organize all addresses so for address X give me all changes that happened to product X using tangle without the need for any filters. If you have any better solution or feedback please leave a comment. Thanks.

Project source code

https://github.com/yehia67/Tracker-api/