{"info":{"_postman_id":"0bffb109-7af9-4ce3-b269-a53cb1e5c8e8","name":"NGSI-LD Working with Linked Data","description":"[![FIWARE Core Context Management](https://nexus.lab.fiware.org/repository/raw/public/badges/chapters/core.svg)](https://github.com/FIWARE/catalogue/blob/master/core/README.md)\n[![NGSI LD](https://img.shields.io/badge/NGSI-linked_data-red.svg)](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.01.01_60/gs_CIM009v010101p.pdf)\n\nThis tutorial teaches FIWARE users how to architect and design a system based on **linked data** and to alter linked\ndata context programmatically. The tutorial extends the knowledge gained from the equivalent\n[NGSI-v2 tutorial](https://github.com/FIWARE/tutorials.Accessing-Context/) and enables a user understand how to write\ncode in an [NGSI-LD](https://www.etsi.org/deliver/etsi_gs/CIM/001_099/009/01.01.01_60/gs_CIM009v010101p.pdf) capable\n[Node.js](https://nodejs.org/) [Express](https://expressjs.com/) application in order to retrieve and alter context\ndata. This removes the need to use the command-line to invoke cUrl commands.\n\nThe tutorial is mainly concerned with discussing code written in Node.js, however some of the results can be checked by\nmaking [cUrl](https://ec.haxx.se/) commands.\n\nThe `docker-compose` files for this tutorial can be found on GitHub: \n\n![GitHub](https://fiware.github.io/tutorials.Working-with-Linked-Data/icon/GitHub-Mark-32px.png) [FIWARE 603: Traversing Linked Data Programmatically](https://github.com/Fiware/tutorials.Working-with-Linked-Data)\n\n\n# Working with Linked Data Entities\n\n> -   “This is the house that Jack built.\n> -   This is the malt that lay in the house that Jack built.\n> -   This is the rat that ate the malt<br/> That lay in the house that Jack built.\n> -   This is the cat<br/> That killed the rat that ate the malt<br/> That lay in the house that Jack built.\n> -   This is the dog that chased the cat<br/> That killed the rat that ate the malt<br/> That lay in the house that\n>     Jack built.”\n>\n> ― This Is the House That Jack Built, Traditional English Nursery Rhyme\n\nNSGI-LD is an evolution of NGSI-v2, so it should not be surprising that Smart solutions based on NSGI-LD will need to\ncover the same basic scenarios as outlined in the previous NGSI-v2\n[tutorial](https://github.com/FIWARE/tutorials.Accessing-Context/) on programatic data access.\n\nNGSI-LD Linked data formalizes the structure of context entities to a greater degree, through restricting data\nattributes to be defined as either _Property_ attributes or _Relationship_ attributes only. This means that it is\npossible to traverse the context data graph with greater certainty when moving from one _Relationship_ to another. All\nthe context data entities within the system are defined by JSON-LD data models, which are formally defined by\nreferencing a context file, and this programatic definition should guarantee that the associated linked entity exists.\n\nThree basic data access scenarios for the supermaket are defined below:\n\n-   Reading Data - e.g. Give me all the data for the **Building** entity `urn:ngsi-ld:Building:store001`\n-   Aggregation - e.g. Combine the **Products** entities sold in **Building** `urn:ngsi-ld:Building:store001` and\n    display the goods for sale\n-   Altering context within the system - e.g. Make a sale of a product:\n    -   Update the daily sales records by the price of the **Product**\n    -   decrement the `numberOfItems` of the **Shelf** entity\n    -   Create a new Transaction Log record showing the sale has occurred\n    -   Raise an alert in the warehouse if less than 10 objects remain on sale\n    -   etc.\n\nFurther advanced scenarios will be covered in later tutorials\n\n## Linked Data Entities within a stock management system\n\nThe supermarket data created in the [previous tutorial](https://github.com/FIWARE/tutorials.Relationships-Linked-Data/)\nwill be loaded into the context broker. The existing relationships between the entities are defined as shown below:\n\n![](https://fiware.github.io/tutorials.Relationships-Linked-Data/img/entities-ld.png)\n\nThe **Building**, **Product**, **Shelf** and **StockOrder** entities will be used to display data on the frontend of our\ndemo application.\n\n## The teaching goal of this tutorial\n\nThe aim of this tutorial is to improve developer understanding of programmatic access of context data through defining\nand discussing a series of generic code examples covering common data access scenarios. For this purpose a simple\nNode.js Express application will be created.\n\nThe intention here is not to teach users how to write an application in Express - indeed any language could have been\nchosen. It is merely to show how **any** sample programming language could be used alter the context to achieve the\nbusiness logic goals.\n\nObviously, your choice of programming language will depend upon your own business needs - when reading the code below\nplease keep this in mind and substitute Node.js with your own programming language as appropriate.\n\n# Stock Management Frontend\n\nAll the code Node.js Express for the demo can be found within the `ngsi-ld` folder within the GitHub repository.\n[Stock Management example](https://github.com/FIWARE/tutorials.Step-by-Step/tree/master/context-provider). The\napplication runs on the following URLs:\n\n-   `http://localhost:3000/app/store/urn:ngsi-ld:Building:store001`\n-   `http://localhost:3000/app/store/urn:ngsi-ld:Building:store002`\n-   `http://localhost:3000/app/store/urn:ngsi-ld:Building:store003`\n-   `http://localhost:3000/app/store/urn:ngsi-ld:Building:store004`\n\n> :information_source: **Tip** Additionally, you can also watch the status of recent requests yourself by following the\n> container logs or viewing information on `localhost:3000/app/monitor` on a web browser.\n>\n> ![FIWARE Monitor](https://fiware.github.io/tutorials.Accessing-Context/img/monitor.png)\n\n# Prerequisites\n\n## Docker\n\nTo keep things simple all components will be run using [Docker](https://www.docker.com). **Docker** is a container\ntechnology which allows to different components isolated into their respective environments.\n\n-   To install Docker on Windows follow the instructions [here](https://docs.docker.com/docker-for-windows/)\n-   To install Docker on Mac follow the instructions [here](https://docs.docker.com/docker-for-mac/)\n-   To install Docker on Linux follow the instructions [here](https://docs.docker.com/install/)\n\n**Docker Compose** is a tool for defining and running multi-container Docker applications. A\n[YAML file](https://raw.githubusercontent.com/fiware/tutorials.Relationships-Linked-Data/master/docker-compose.yml) is\nused configure the required services for the application. This means all container services can be brought up in a\nsingle command. Docker Compose is installed by default as part of Docker for Windows and Docker for Mac, however Linux\nusers will need to follow the instructions found [here](https://docs.docker.com/compose/install/)\n\n## Cygwin\n\nWe will start up our services using a simple bash script. Windows users should download [cygwin](http://www.cygwin.com/)\nto provide a command-line functionality similar to a Linux distribution on Windows.\n\n# Architecture\n\nThe demo Supermarket application will send and receive NGSI-LD calls to a compliant context broker. Since the NGSI-LD\ninterface is available on an experimental version of the\n[Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/), the demo application will only make use of one\nFIWARE component.\n\nCurrently, the Orion Context Broker relies on open source [MongoDB](https://www.mongodb.com/) technology to keep\npersistence of the context data it holds. To request context data from external sources, a simple Context Provider NGSI\nproxy has also been added. To visualize and interact with the Context we will add a simple Express application\n\nTherefore, the architecture will consist of three elements:\n\n-   The [Orion Context Broker](https://fiware-orion.readthedocs.io/en/latest/) which will receive requests using\n    [NGSI](https://fiware.github.io/specifications/OpenAPI/ngsiv2)\n-   The underlying [MongoDB](https://www.mongodb.com/) database :\n    -   Used by the Orion Context Broker to hold context data information such as data entities, subscriptions and\n        registrations\n-   The **Stock Management Frontend** which will:\n    -   Display store information\n    -   Show which products can be bought at each store\n    -   Allow users to \"buy\" products and reduce the stock count.\n\nSince all interactions between the elements are initiated by HTTP requests, the entities can be containerized and run\nfrom exposed ports.\n\n![](https://fiware.github.io/tutorials.Accessing-Context/img/architecture.png)\n\nThe necessary configuration information for the **Context Provider NGSI proxy** can be seen in the services section the\nof the associated `docker-compose.yml` file:\n\n```yaml\ntutorial:\n    image: fiware/tutorials.context-provider\n    hostname: context-provider\n    container_name: fiware-tutorial\n    networks:\n        - default\n    expose:\n        - \"3000\"\n    ports:\n        - \"3000:3000\"\n    environment:\n        - \"DEBUG=tutorial:*\"\n        - \"WEB_APP_PORT=3000\"\n        - \"NGSI_VERSION=ngsi-ld\"\n        - \"CONTEXT_BROKER=http://orion:1026/ngsi-ld/v1\"\n```\n\nThe `tutorial` container is driven by environment variables as shown:\n\n| Key            | Value                          | Description                                                               |\n| -------------- | ------------------------------ | ------------------------------------------------------------------------- |\n| DEBUG          | `tutorial:*`                   | Debug flag used for logging                                               |\n| WEB_APP_PORT   | `3000`                         | Port used by the Context Provider NGSI proxy and web-app for viewing data |\n| CONTEXT_BROKER | `http://orion:1026/ngsi-ld/v1` | URL of the context broker to connect to update context                    |\n\nThe other `tutorial` container configuration values described in the YAML file are not used in this section of the\ntutorial.\n\nThe configuration information for MongoDB and the Orion Context Broker has been described in a\n[previous tutorial](https://github.com/FIWARE/tutorials.Relationships-Linked-Data/)\n\n# Start Up\n\nAll services can be initialised from the command-line by running the\n[services](https://github.com/FIWARE/tutorials.Relationships-Linked-Data/blob/master/services) Bash script provided\nwithin the repository. Please clone the repository and create the necessary images by running the commands as shown:\n\n```bash\ngit clone https://github.com/FIWARE/tutorials.Working-with-Linked-Data.git\ncd tutorials.Working-with-Linked-Data\n\n./services orion\n```\n\n> **Note:** If you want to clean up and start over again you can do so with the following command:\n>\n> ```\n> ./services stop\n> ```\n","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json"},"item":[{"name":"Reading Linked Data","item":[{"name":"Retrieve a known Store","id":"948447ac-15b1-4cc6-ac0a-ac7cff46ed56","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"","value":"","type":"text","disabled":true}],"url":{"raw":"http://{{orion}}/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001/?options=keyValues","protocol":"http","host":["{{orion}}"],"path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001",""],"query":[{"key":"options","value":"keyValues"}]},"description":"This example reads the context data of a given **Store** entity to display the results on screen. Reading entity data\ncan be done using the `ngsiLD.readEntity()` method - this will fill out the URL for the GET request and make the\nnecessary HTTP call in an asynchronous fashion:\n\n```javascript\nasync function displayStore(req, res) {\n    const store = await ngsiLD.readEntity(\n        req.params.storeId,\n        { options: \"keyValues\" },\n        ngsiLD.setHeaders(req.session.access_token, LinkHeader)\n    );\n\n    return res.render(\"store\", { title: store.name, store });\n}\n```\n\nThe function above also sends some standard HTTP Headers as part of the request - these are defined in the\n`setHeaders()` function.\n\nWithin an NGSI-LD-based system, the usual default HTTP headers would include a `Link` header to send the JSON-LD context\nand a `Content-Type` header to identify the request as `application/ld+json` (note that every NGSI-LD request is valid\nJSON_LD since NGSI-LD is a subset of JSON-LD). Other additional headers such as `X-Auth-Token` can be added to enable\nOAuth2 security.\n\n```javascript\nfunction setHeaders(accessToken, link, contentType) {\n    const headers = {};\n    if (accessToken) {\n        headers[\"X-Auth-Token\"] = accessToken;\n    }\n    if (link) {\n        headers.Link = link;\n    }\n    if (contentType) {\n        headers[\"Content-Type\"] = contentType || \"application/ld+json\";\n    }\n    return headers;\n}\n```\n\nWithin the `lib/ngsi-ld.js` library file, the `BASE_PATH` defines the location of the Orion Context Broker, reading a\ndata entity is simply a wrapper around an asynchronous HTTP GET request passing the appropriate headers\n\n```javascript\nconst BASE_PATH = process.env.CONTEXT_BROKER || \"http://localhost:1026/ngsi-ld/v1\";\n\nfunction readEntity(entityId, opts, headers = {}) {\n    return request({\n        qs: opts,\n        url: BASE_PATH + \"/entities/\" + entityId,\n        method: \"GET\",\n        headers,\n        json: true\n    });\n}\n```"},"response":[],"_postman_id":"948447ac-15b1-4cc6-ac0a-ac7cff46ed56"}],"id":"38a99fb3-d2ed-4088-9828-1e1755ab8983","description":"The code under discussion can be found within the `ngsi-ld/store` controller in the\n[Git Repository](https://github.com/FIWARE/tutorials.Step-by-Step/blob/master/context-provider/controllers/ngsi-ld/store.js)\n\nGoto `http://localhost:3000/app/store/urn:ngsi-ld:Building:store001` to display and interact with the working\nSupermarket data application.\n\n### Initializing the library\n\nAs usual, the code for HTTP access can be split out from the business logic of the Supermarket application itself. The\nlower level calls have been placed into a library file, which simplifies the codebase. This needs to be included in the\nheader of the file as shown. Some constants are also required - for the Supermarket data, the `LinkHeader` is used to\ndefine location of the data models JSON-LD context as\n`https://fiware.github.io/tutorials.Step-by-Step/tutorials-context.jsonld`.\n\n```javascript\nconst ngsiLD = require(\"../../lib/ngsi-ld\");\n\nconst LinkHeader =\n    '<https://fiware.github.io/tutorials.Step-by-Step/tutorials-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\">';\n```","event":[{"listen":"prerequest","script":{"id":"f7057145-c2b9-4699-be04-77675a4bd430","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"05969c16-3c69-423d-87c6-6d5bb3e7fa27","type":"text/javascript","exec":[""]}}],"_postman_id":"38a99fb3-d2ed-4088-9828-1e1755ab8983"},{"name":"Aggregating and Traversing Linked Data","item":[{"name":"Find Shelves within a known Store","id":"0aef6ba6-8dde-406f-8d20-371b8874b3cc","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"","value":"","type":"text","disabled":true}],"url":{"raw":"http://{{orion}}/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001/?options=keyValues&attrs=furniture","protocol":"http","host":["{{orion}}"],"path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001",""],"query":[{"key":"options","value":"keyValues"},{"key":"attrs","value":"furniture"}]},"description":"To access the `furniture` attribute of a known **Building** entity, a `keyValues` request is made using the `attrs`\nparameter.\n\n```javascript\nconst building = await ngsiLD.readEntity(\n    req.params.storeId,\n    {\n        type: \"Building\",\n        options: \"keyValues\",\n        attrs: \"furniture\"\n    },\n    ngsiLD.setHeaders(req.session.access_token, LinkHeader)\n);\n```\n\nThe response is a JSON Object which includes a `furniture` attribute which can be manipulated further."},"response":[],"_postman_id":"0aef6ba6-8dde-406f-8d20-371b8874b3cc"},{"name":"Retrieve Stocked Products from Shelves","id":"9fb4a313-6ec3-4fe7-9b2e-c0ebf6ff1b52","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Accept","value":"application/json","type":"text"},{"key":"","value":"","type":"text","disabled":true}],"url":{"raw":"http://{{orion}}/ngsi-ld/v1/entities/?type=Shelf&options=keyValues&attrs=stocks,numberOfItems&id=urn:ngsi-ld:Shelf:unit001,urn:ngsi-ld:Shelf:unit002,urn:ngsi-ld:Shelf:unit003","protocol":"http","host":["{{orion}}"],"path":["ngsi-ld","v1","entities",""],"query":[{"key":"type","value":"Shelf"},{"key":"options","value":"keyValues"},{"key":"attrs","value":"stocks,numberOfItems"},{"key":"id","value":"urn:ngsi-ld:Shelf:unit001,urn:ngsi-ld:Shelf:unit002,urn:ngsi-ld:Shelf:unit003"}]},"description":"To retrieve a series of **Shelf** entities, the `ngsiLD.listEntities()` function is called and filtered using the `id`\nparameter. The `id` is just a comma separated list taken from the request above.\n\n```javascript\nlet productsList = await ngsiLD.listEntities(\n    {\n        type: \"Shelf\",\n        options: \"keyValues\",\n        attrs: \"stocks,numberOfItems\",\n        id: building.furniture.join(\",\")\n    },\n    ngsiLD.setHeaders(req.session.access_token, LinkHeader)\n);\n```\n\n`listEntities()` is another function within the `lib/ngsi-ld.js` library file\n\n```javascript\nfunction listEntities(opts, headers = {}) {\n    return request({\n        qs: opts,\n        url: BASE_PATH + \"/entities\",\n        method: \"GET\",\n        headers,\n        json: true\n    });\n}\n```\n\nThe response is a JSON Array of **Shelf** entities which includes as `stocks` attribute which can be manipulated\nfurther. The code below extracts the ids for later use.\n\n```javascript\nconst stockedProducts = [];\n\nproductsList = _.groupBy(productsList, e => {\n    return e.stocks;\n});\n_.forEach(productsList, (value, key) => {\n    stockedProducts.push(key);\n});\n```"},"response":[],"_postman_id":"9fb4a313-6ec3-4fe7-9b2e-c0ebf6ff1b52"},{"name":"Retrieve Products from Shelves","id":"2c9b3642-1362-4de5-a3ac-505032c66e78","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Accept","value":"application/json","type":"text"},{"key":"","value":"","type":"text","name":"Accept","disabled":true}],"url":{"raw":"http://{{orion}}/ngsi-ld/v1/entities/?type=Product&options=keyValues&attrs=name,price&id=urn:ngsi-ld:Product:001,urn:ngsi-ld:Product:003,urn:ngsi-ld:Product:004","protocol":"http","host":["{{orion}}"],"path":["ngsi-ld","v1","entities",""],"query":[{"key":"type","value":"Product"},{"key":"options","value":"keyValues"},{"key":"attrs","value":"name,price"},{"key":"id","value":"urn:ngsi-ld:Product:001,urn:ngsi-ld:Product:003,urn:ngsi-ld:Product:004"}]},"description":"To retrieve a series of **Product** entities, the `ngsiLD.listEntities()` function is once again called and filtered\nusing the `id` parameter. The `id` is just a comma separated list taken from the request above.\n\n```javascript\nlet productsInStore = await ngsiLD.listEntities(\n    {\n        type: \"Product\",\n        options: \"keyValues\",\n        attrs: \"name,price\",\n        id: stockedProducts.join(\",\")\n    },\n    headers\n);\n```\n\nThe response is a JSON Array of **Product** entities which are then displayed on screen."},"response":[],"_postman_id":"2c9b3642-1362-4de5-a3ac-505032c66e78"}],"id":"7aab492a-fb18-48ca-80ad-0ee5b0085ddb","description":"To display information at the till, it is necessary to discover information about the products found within a Store.\nFrom the Data Entity diagram we can ascertain that:\n\n-   **Building** entities hold related **Shelf** information within the `furniture` _Relationship_\n-   **Shelf** entities hold related **Product** information within the `stocks` _Relationship_\n-   Products hold `name` and `price` as _Property_ attributes of the **Product** entity itself.\n\nTherefore the code for the `displayTillInfo()` method will consist of the following steps.\n\n1. Make a request to the Context Broker to _find shelves within a known store_\n2. Reduce the result to a `id` parameter and make a second request to the Context Broker to _retrieve stocked products\n   from shelves_\n3. Reduce the result to a `id` parameter and make a third request to the Context Broker to _retrieve product details for\n   selected shelves_\n\nTo users familar with database joins, it may seem strange being forced to making a series of requests like this, however\nit is necessary due to scalability issues/concerns in a large distributed setup. Direct join requests are not possible\nwith NGSI-LD.","_postman_id":"7aab492a-fb18-48ca-80ad-0ee5b0085ddb"},{"name":"Updating Linked Data","item":[{"name":"Find a shelf stocking a product","id":"c6793013-356e-48c1-8f01-1e5a538fe7bb","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text","disabled":true},{"key":"Accept","value":"application/json","type":"text"}],"url":{"raw":"http://{{orion}}/ngsi-ld/v1/entities/?type=Shelf&options=keyValues&q=numberOfItems>0;locatedIn==\"urn:ngsi-ld:Building:store001\";stocks==\"urn:ngsi-ld:Product:001\"","protocol":"http","host":["{{orion}}"],"path":["ngsi-ld","v1","entities",""],"query":[{"key":"type","value":"Shelf"},{"key":"options","value":"keyValues"},{"key":"q","value":"numberOfItems>0;locatedIn==\"urn:ngsi-ld:Building:store001\";stocks==\"urn:ngsi-ld:Product:001\""}]},"description":"To retrieve a series of **Shelf** entities, the `ngsiLD.listEntities()` function is called. It is important to retrieve\nthe current context before amending it, so the `q` parameter is used to only retrieve a shelf from the correct store\ncontaining the correct product. This request is only possible because the **Shelf** data model has been designed to hold\n_relationships_ with both **Building** and **Product**.\n\n```javascript\nconst shelf = await ngsiLD.listEntities(\n    {\n        type: \"Shelf\",\n        options: \"keyValues\",\n        attrs: \"stocks,numberOfItems\",\n        q: 'numberOfItems>0;locatedIn==\"' + req.body.storeId + '\";stocks==\"' + req.body.productId + '\"',\n        limit: 1\n    },\n    headers\n);\n```"},"response":[],"_postman_id":"c6793013-356e-48c1-8f01-1e5a538fe7bb"},{"name":"Update the state of a shelf","id":"e42434d6-2d8f-4337-b892-048f7263d86c","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PATCH","header":[{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Content-Type","value":"application/json","type":"text"},{"key":"Accept","value":"application/json","type":"text","name":"Accept","disabled":true}],"body":{"mode":"raw","raw":"{ \"numberOfItems\": { \"type\": \"Property\", \"value\": 9 } }"},"url":"http://{{orion}}/ngsi-ld/v1/entities/urn:ngsi-ld:Shelf:unit001/attrs","description":"To update an entity a PATCH request is made using the id of the **Shelf** returned in the previous request\n\n```javascript\nconst count = shelf[0].numberOfItems - 1;\nawait ngsiLD.updateAttribute(\n    shelf[0].id,\n    { numberOfItems: { type: \"Property\", value: count } },\n    ngsiLD.setHeaders(req.session.access_token, LinkHeader)\n);\n```\n\nThe asynchronous PATCH request is found in the `updateAttribute()` function within the `lib/ngsi-ld.js` library file\n\n```javascript\nfunction updateAttribute(entityId, body, headers = {}) {\n    return request({\n        url: BASE_PATH + \"/entities/\" + entityId + \"/attrs\",\n        method: \"PATCH\",\n        body,\n        headers,\n        json: true\n    });\n}\n```"},"response":[],"_postman_id":"e42434d6-2d8f-4337-b892-048f7263d86c"}],"id":"95622d98-7782-45f5-8406-63cfd395bf52","_postman_id":"95622d98-7782-45f5-8406-63cfd395bf52"},{"name":"Interoperability using Linked Data","item":[{"name":"Creating an Entity using  an Alternate Schema","id":"8f654466-2754-40b0-b0d4-3cfe181e687e","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/ld+json"}],"body":{"mode":"raw","raw":"{\n    \"id\": \"urn:ngsi-ld:Building:store005\",\n    \"type\": \"ビル\",\n    \"カテゴリー\": {\n    \t\"type\": \"VocabularyProperty\",\n        \"vocab\": [\"コマーシャル\"]\n    },\n    \"住所\": {\n        \"type\": \"Property\",\n        \"value\": {\n            \"streetAddress\": \"Eisenacher Straße 98\",\n            \"addressRegion\": \"Berlin\",\n            \"addressLocality\": \"Marzahn\",\n            \"postalCode\": \"12685\"\n        }\n    },\n    \"場所\": {\n        \"type\": \"GeoProperty\",\n        \"value\": {\n             \"type\": \"Point\",\n             \"coordinates\": [13.5646, 52.5435]\n        }\n    },\n    \"名前\": {\n        \"type\": \"Property\",\n        \"value\": \"Yuusui-en\"\n    },\n    \"@context\":\"http://context/japanese-user-context.jsonld\"\n}"},"url":"http://{{orion}}/ngsi-ld/v1/entities/","description":"When creating a data entity, short names for all of the URIs mapped in the Japanese JSON-LD `@context` can be used freely in the payload of the request.\n\nAs can be seen in the example below, attribute names and enumerated values (such as `る建物`  = `Building`) can be used throughout. The  NGSI-LD specification mandates that the attributes defined in the NGSI-LD API (i.e. the core `@context`) are used to define the attributes. Therefore elements of the request such as `id` `type` and `Property` remain unchanged, although as we will see below this can be circumvented.\n\nOur Japanese context provider can create a new `Building` using the request below:"},"response":[],"_postman_id":"8f654466-2754-40b0-b0d4-3cfe181e687e"},{"name":"Reading an Entity using the default schema","id":"4d6bc4df-3235-4aff-b847-e6e6486608a2","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/json","disabled":true},{"key":"Link","value":"<{{datamodels-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Accept","value":"application/json","type":"text","name":"Accept","disabled":true}],"url":"http://{{orion}}/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store005","description":"Within the context broker the full URIs are used to refer to the attributes and enumerations. Even though it uses different attribute short names, the Japanese JSON-LD `@context`  file agrees with the standard tutorial context about the full URIs used for a **Building** entity  - effectively it is using the same data model.\n\nTherefore it is possible to request the new **Building** (created using the Japanese data model) and have it return using the short names specified in the standard tutorial JSON-LD `@context`, this is done by supplying the `Link` header is pointing to the tutorial JSON-LD `@context` file.\n\nThe response is an ordinary **Building** entity which standard attribute names (such as `name` and `location` and it also returns the standard enumeration for **Building** `category`.\n\nThis means that our Supermarket application is able to display the new building without any modification to the underlying codebase. The data is interoperable.\n\nGoto `http://localhost:3000/app/store/urn:ngsi-ld:Building:store005` to show that the new **Building** can be displayed:\n\n![](https://fiware.github.io/tutorials.Working-with-Linked-Data/img/store5.png)"},"response":[],"_postman_id":"4d6bc4df-3235-4aff-b847-e6e6486608a2"},{"name":"Reading an Entity using an alternate schema","id":"4476a747-f6e4-42c4-92ad-c8b4d2b8cf0b","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/ld+json","disabled":true},{"key":"Link","value":"<{{japanese-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Accept","value":"application/json","type":"text","name":"Accept"}],"url":"http://{{orion}}/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store003","description":"With one exception, there is no hierarchy defined within NGSI-LD `@context` files - any defined `@context` is therefore possible to read any of the existing **Building** entities and apply the Japanese `@context`. The `@context` to used is supplied in the `Link` header.\n\nThe response is mixed - it uses  attribute names and enumerations defined in `japanese-context.jsonld` with some exceptions. NSGI-LD **is not** JSON-LD, in that the core context is always applied after the contexts received in the `Link` header. Since `name` and `location` are reserved attribute names, they are supplied using the default core context."},"response":[],"_postman_id":"4476a747-f6e4-42c4-92ad-c8b4d2b8cf0b"},{"name":"Applying Entity Expansion/Compation","id":"13638e05-9988-4ba0-9ef9-5c9a2193c074","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","value":"application/ld+json","disabled":true},{"key":"Accept","value":"application/ld+json","type":"text","name":"Accept"},{"key":"Link","value":"<{{japanese-context.jsonld}}>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text","disabled":true}],"url":{"raw":"http://{{context-provider}}/japanese/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store005?options=keyValues","protocol":"http","host":["{{context-provider}}"],"path":["japanese","ngsi-ld","v1","entities","urn:ngsi-ld:Building:store005"],"query":[{"key":"options","value":"keyValues"}]},"description":"The Within JSON-LD there is a standard mechanism for applying and altering local attribute names. The response from the context broker will always be valid NGSI-LD. NGSI-LD is just a structured subset of JSON-LD, so further changes can be made to use the data received as JSON.\n\nIf we need to overide the core NGSI-LD context, we can apply an additional expansion/compaction operation over the response to retrive the data in a fully converted fashion for local use.  \n\nJSON-LD libraries already exist to do this work.\n\n```javascript\nconst coreContext = require('./jsonld-context/ngsi-ld.json');\nconst japaneseContext = require('./jsonld-context/japanese.json');\n\nfunction translateRequest(req, res) {\n  request({\n    url: BASE_PATH + req.path, \n    method: req.method,\n    headers: req.headers,\n    qs: req.query,\n    json: true\n  })\n    .then(async function(cbResponse) {\n      cbResponse['@context'] = coreContext;\n      const expanded = await jsonld.expand(cbResponse);\n      const compacted = await jsonld.compact(expanded, japaneseContext);\n      delete compacted['@context'];\n      return res.send(compacted);\n    })\n    .catch(function(err) {\n      return res.send(err);\n    });\n}\n```\n\nThe response after the expansion/compaction operation is data which uses all of the preferred attribute names - this is **no longer**  valid NGSI-LD, but would be of use if the receiving system requests data in this format.\n\nNote that the reverse expansion/compaction operation could be used to convert this JSON back into a valid NSGI-LD payload before sending data to the context broker.\n\n\n#### :arrow_forward: Video: JSON-LD Compaction & Expansion\n\n[![](http://img.youtube.com/vi/Tm3fD89dqRE/0.jpg)](https://www.youtube.com/watch?v=Tm3fD89dqRE \"JSON-LD Compaction & Expansion\")\n\nClick on the image above to watch a video JSON-LD expansion and compaction with reference to the `@context`."},"response":[],"_postman_id":"13638e05-9988-4ba0-9ef9-5c9a2193c074"}],"id":"aadf82b7-5d6f-4928-acf2-ec169b0d636c","description":"An alternative Japanese JSON-LD `@context` file has been created and published to an external server. The file can be found here: `https://fiware.github.io/tutorials.Step-by-Step/japanese-context.jsonld`. Alternate data mappings can be found for all attribute names used within the tutorials.\n\n> **Note**: For comparision the standard tutorial JSON-LD `@context` file can be found here:\n> `https://fiware.github.io/tutorials.Step-by-Step/tutorials-context.jsonld`","event":[{"listen":"prerequest","script":{"id":"e93af0c5-33d3-4b9b-b5c5-675f2b6ec644","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"611eaae5-2a6a-41d8-a764-8c7b0ad917b9","type":"text/javascript","exec":[""]}}],"_postman_id":"aadf82b7-5d6f-4928-acf2-ec169b0d636c"}],"event":[{"listen":"prerequest","script":{"id":"7388436e-e658-41f9-873f-082a1182fdec","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"c61db76f-e1ce-4bd6-9f35-6584d196e068","type":"text/javascript","exec":[""]}}],"variable":[{"key":"orion","value":"localhost:1026"},{"key":"datamodels-context.jsonld","value":"http://context/user-context.jsonld"},{"key":"device-edge","value":"localhost:1027"},{"key":"context-provider","value":"localhost:3000"},{"key":"japanese-context.jsonld","value":"http://context/japanese-user-context.jsonld"}]}