{"info":{"_postman_id":"8d924393-5886-4687-95ef-9b2648da537c","name":"NGSI-LD Subscriptions and Registrations","description":"<html><head></head><body><p>This tutorial discusses the usage of subscriptions and registrations within NGSI-LD and highlights the similarities and\ndifferences between the equivalent NGSI-v2 and NGSI-LD operations. The tutorial is an analogue of the original\ncontext-provider and subscriptions tutorials but uses API calls from the <strong>NGSI-LD</strong> interface throughout.</p>\n<p>The <code>docker-compose</code> files for this tutorial can be found on GitHub: </p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/icon/GitHub-Mark-32px.png\" alt=\"GitHub\"> <a href=\"https://github.com/Fiware/tutorials.LD-Subscriptions-Registrations\">FIWARE 604. Linked Data Subscriptions and Registrations</a></p>\n<h1 id=\"understanding-linked-data-subscriptions-and-registrations\">Understanding Linked Data Subscriptions and Registrations</h1>\n<blockquote>\n<p>“Do not repeat after me words that you do not understand. Do not merely put on a mask of my ideas, for it will be an\nillusion and you will thereby deceive yourself.”</p>\n<p>― Jiddu Krishnamurti</p>\n</blockquote>\n<p>NGSI-LD Subscriptions and Registrations provide the basic mechanism to allow the components within a Smart Linked Data\nSolution to interact with each other.</p>\n<p>As a brief reminder, within a distributed system, subscriptions inform a third party component that a change in the\ncontext data has occurred (and the component needs to take further actions), whereas registrations tell the context\nbroker that additional context information is available from another source.</p>\n<p>Both of these operations require that the receiving component fully understands the requests it receives, and is capable\nof creating and interpreting the resultant payloads. The differences here between NGSI-v2 and NGSI-LD operations is\nsmall, but there has been a minor amendment to facilite the incorporation of linked data concepts, and therefore the\ncontract between the various components has changed to include minor updates.</p>\n<h2 id=\"entities-within-a-stock-management-system\">Entities within a stock management system</h2>\n<p>The relationship between our Linked Data entities is defined as shown, in addition to the existing data, the <code>tweets</code>\nattribute will be supplied by a <em>Context Provider</em>. In all other respects this model remains the same as the\n<a href=\"https://github.com/FIWARE/tutorials.Working-with-Linked-Data/\">previous tutorial</a> :</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/entities.png\" alt=\"\"></p>\n<h2 id=\"stock-management-frontend\">Stock Management frontend</h2>\n<p>The simple Node.js Express application has updated to use NGSI-LD in the previous\n<a href=\"https://github.com/FIWARE/tutorials.Working-with-Linked-Data/\">tutorial</a>. We will use the monitor page to watch the\nstatus of recent requests, and a two store pages to buy products. Once the services are running these pages can be\naccessed from the following URLs:</p>\n<h4 id=\"event-monitor\">Event Monitor</h4>\n<p>The event monitor can be found at: <code>http://localhost:3000/app/monitor</code></p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/monitor.png\" alt=\"FIWARE Monitor\"></p>\n<h4 id=\"store-001\">Store 001</h4>\n<p>Store001 can be found at: <code>http://localhost:3000/app/store/urn:ngsi-ld:Building:store001</code></p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/store.png\" alt=\"Store\"></p>\n<h4 id=\"store-002\">Store 002</h4>\n<p>Store002 can be found at: <code>http://localhost:3000/app/store/urn:ngsi-ld:Building:store002</code></p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/store2.png\" alt=\"Store2\"></p>\n<h1 id=\"architecture\">Architecture</h1>\n<p>The 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<a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a>, the demo application will only make use of one\nFIWARE component.</p>\n<p>Currently, the Orion Context Broker relies on open source <a href=\"https://www.mongodb.com/\">MongoDB</a> 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</p>\n<p>Therefore, the architecture will consist of four elements:</p>\n<ul>\n<li>The <a href=\"https://fiware-orion.readthedocs.io/en/latest/\">Orion Context Broker</a> which will receive requests using\n<a href=\"https://forge.etsi.org/swagger/ui/?url=https://forge.etsi.org/gitlab/NGSI-LD/NGSI-LD/raw/master/spec/updated/full_api.json\">NGSI-LD</a></li>\n<li>The underlying <a href=\"https://www.mongodb.com/\">MongoDB</a> database :<ul>\n<li>Used by the Orion Context Broker to hold context data information such as data entities, subscriptions and\nregistrations</li>\n</ul>\n</li>\n<li>The <strong>Context Provider NGSI</strong> proxy which will:<ul>\n<li>receive requests using\n<a href=\"https://forge.etsi.org/swagger/ui/?url=https://forge.etsi.org/gitlab/NGSI-LD/NGSI-LD/raw/master/spec/updated/full_api.json#/\">NGSI-LD</a></li>\n<li>makes requests to publicly available data sources using their own APIs in a proprietary format</li>\n<li>returns context data back to the Orion Context Broker in\n<a href=\"https://forge.etsi.org/swagger/ui/?url=https://forge.etsi.org/gitlab/NGSI-LD/NGSI-LD/raw/master/spec/updated/full_api.json#/\">NGSI-LD</a>\nformat.</li>\n</ul>\n</li>\n<li>The <strong>Stock Management Frontend</strong> which will:<ul>\n<li>Display store information</li>\n<li>Show which products can be bought at each store</li>\n<li>Allow users to \"buy\" products and reduce the stock count.</li>\n</ul>\n</li>\n</ul>\n<p>Since all interactions between the elements are initiated by HTTP requests, the entities can be containerized and run\nfrom exposed ports.</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/architecture.png\" alt=\"\"></p>\n<p>The necessary configuration information can be seen in the services section of the associated <code>orion-ld.yml</code> file. It\nhas been described in a <a href=\"https://github.com/FIWARE/tutorials.Working-with-Linked-Data/\">previous tutorial</a></p>\n<h1 id=\"start-up\">Start Up</h1>\n<p>All services can be initialised from the command-line by running the\n<a href=\"https://github.com/FIWARE/tutorials.LD-Subscriptions-Registrations/blob/master/services\">services</a> Bash script provided\nwithin the repository. Please clone the repository and create the necessary images by running the commands as shown:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code class=\"language-bash\">git clone https://github.com/FIWARE/tutorials.LD-Subscriptions-Registrations.git\ncd tutorials.LD-Subscriptions-Registrations\n\n./services orion\n</code></pre>\n<blockquote>\n<p><strong>Note:</strong> If you want to clean up and start over again you can do so with the following command:</p>\n<pre class=\"click-to-expand-wrapper is-snippet-wrapper\"><code>./services stop\n</code></pre></blockquote>\n</body></html>","schema":"https://schema.getpostman.com/json/collection/v2.0.0/collection.json","toc":[{"content":"Understanding Linked Data Subscriptions and Registrations","slug":"understanding-linked-data-subscriptions-and-registrations"},{"content":"Architecture","slug":"architecture"},{"content":"Start Up","slug":"start-up"}],"owner":"513743","collectionId":"8d924393-5886-4687-95ef-9b2648da537c","publishedId":"SzfDvjN5","public":true,"customColor":{"top-bar":"FFFFFF","right-sidebar":"303030","highlight":"233C68"},"publishDate":"2020-04-28T08:28:23.000Z"},"item":[{"name":"Using Subscriptions with NGSI-LD","item":[{"name":"Create a Subscription ( Store 1) - Low Stock","id":"00dca035-3e58-4d50-a838-ddf33acced2e","protocolProfileBehavior":{"disableBodyPruning":true,"disabledSystemHeaders":{"accept":true}},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/ld+json","type":"text","name":"Accept"},{"key":"Accept","value":"application/ld+json","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"description\": \"Notify me of low stock in Store 001\",\n    \"type\": \"Subscription\",\n    \"entities\": [\n        {\n            \"type\": \"Shelf\"\n        }\n    ],\n    \"watchedAttributes\": [\n        \"numberOfItems\"\n    ],\n    \"q\": \"numberOfItems<10;locatedIn==%22urn:ngsi-ld:Building:store001%22\",\n    \"notification\": {\n        \"attributes\": [\n            \"numberOfItems\",\n            \"stocks\",\n            \"locatedIn\"\n        ],\n        \"format\": \"keyValues\",\n        \"endpoint\": {\n            \"uri\": \"http://tutorial:3000/subscription/low-stock-store001\",\n            \"accept\": \"application/json\"\n        }\n    },\n    \"@context\": \"http://context/user-context.jsonld\"\n}","options":{"raw":{"language":"json"}}},"url":"http://localhost:1026/ngsi-ld/v1/subscriptions","description":"<p>NGSI-LD subscriptions can be set up using the <code>/ngsi-ld/v1/subscriptions/</code> endpoint and in a similar manner to the\nNGSI-v2 <code>/v2/subscriptions</code> endpoint. The payload body is slightly different however. Firstly the linked data <code>@context</code>\nmust be present either as an attribute or in the <code>Link</code> header. If the <code>@context</code> is placed in the body the\n<code>Context-Type</code> header must state that the payload is <code>application/ld+json</code> - i.e. Linked Data plus JSON. The supplied\n<code>@context</code> will also be used when making notifications as part of the notification request.</p>\n<p>The <code>type</code> of the NGSI-LD subscription request is always <code>type=Subscription</code>. The structure of the subscription has\nchanged. When setting up a subscription, there is no longer a separate <code>subject</code> section to the payload, entities to\nwatch and trigger conditions are now set at the same level as the <code>description</code> of the subscription.</p>\n<ul>\n<li><code>condition.attrs</code> has been moved up a level and renamed to <code>watchedAttributes</code></li>\n<li><code>condition.expression</code> has been moved up a level and renamed to <code>q</code></li>\n</ul>\n<p>The <code>notification</code> section of the body states that once the conditions of the subscription have been met, a POST request\ncontaining all affected Shelf entities will be sent to the URL <code>http://tutorial:3000/subscription/low-stock-store001</code>.\nIt is now possible to amend the notification payload by requesting <code>notification.format=keyValues</code> and remove the\n<code>@context</code> from the notification body by stating <code>notification.endpoint.accept=application/json</code>. The <code>@context</code> is not\nlost, it is merely passed as a <code>Link</code> header. In summary, all of the flags within a subscription work in the same manner\nas a GET request to the context broker itself. If no flags are set, a full NGSI-LD response including the <code>@context</code> is\nreturned by default, and the payload can be reduced and amended by adding in further restriction</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"00dca035-3e58-4d50-a838-ddf33acced2e"},{"name":"Create a Subscription ( Store 2) - Low Stock","id":"8f2d21ce-b2ed-4cb9-99e6-bcbee396c434","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","name":"Accept","type":"text","value":"application/json"},{"key":"Link","type":"text","value":"<http://context/user-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\""}],"body":{"mode":"raw","raw":"{\n    \"description\": \"Notify me of low stock in Store 002\",\n    \"type\": \"Subscription\",\n    \"entities\": [\n        {\n            \"type\": \"Shelf\"\n        }, \n        {\n            \"type\": \"Product\"\n        },\n        {\n            \"type\": \"Store\"\n        }\n    ],\n    \"watchedAttributes\": [\n        \"numberOfItems\"\n    ],\n    \"q\": \"numberOfItems<10;locatedIn==%22urn:ngsi-ld:Building:store002%22\",\n    \"notification\": {\n        \"attributes\": [\n            \"numberOfItems\",\n            \"stocks\",\n            \"locatedIn\"\n        ],\n        \"format\": \"keyValues\",\n        \"endpoint\": {\n            \"uri\": \"http://tutorial:3000/subscription/low-stock-store002\",\n            \"accept\": \"application/json\"\n        }\n    }\n}"},"url":"http://localhost:1026/ngsi-ld/v1/subscriptions","description":"<p>This second request fires notifications to a different endpoint (URL\n<code>http://tutorial:3000/subscription/low-stock-store002</code>.) The <code>notification.format=normalized</code> and\n<code>notification.endpoint.accept=application/ld+json</code> will ensure that the <code>@context</code> is passed in the body of the\nnotification request and that the payload will consist of the expanded entities.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"8f2d21ce-b2ed-4cb9-99e6-bcbee396c434"},{"name":"Read Subscription Details","id":"16044836-1be0-43f8-b24f-9c54d4738e38","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Content-Type","name":"Accept","type":"text","value":"application/json"},{"key":"Link","type":"text","value":"<http://context/user-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\""}],"body":{"mode":"raw","raw":""},"url":"http://localhost:1026/ngsi-ld/v1/subscriptions/","description":"<p>Subscription details can be read by making a GET request to the <code>/ngsi-ld/v1/subscriptions/</code>. All subscription CRUD\nactions continue to be mapped to the same HTTP verbs as before. Adding the <code>Accept: application/json</code> will remove the\n<code>@context</code> element from the response body.</p>\n<p>The response consists of the details of the subscriptions within the system. The parameters within the <code>q</code> attribute\nhave been expanded to use the full URIs, as internally the broker consistently uses long names. The differences between\nthe payloads offered by the two subscriptions will be discussed below.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","subscriptions",""],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"16044836-1be0-43f8-b24f-9c54d4738e38"}],"id":"55468fb5-c7c7-45b9-9331-a4f80505d9b1","description":"<p>Goto <code>http://localhost:3000/app/store/urn:ngsi-ld:Building:store001</code> to display and interact with the Supermarket data.</p>\n","event":[{"listen":"prerequest","script":{"id":"5be3c9eb-51f5-4f2b-b757-f7885141514a","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"f1310ca6-1ff9-411f-88a1-6cea4d40421e","type":"text/javascript","exec":[""]}}],"_postman_id":"55468fb5-c7c7-45b9-9331-a4f80505d9b1"},{"name":"Retrieving Subscription Events","item":[],"id":"1cba4850-92d1-4d50-88f4-47e905f18bd1","description":"<p>Open two tabs on a browser. Go to the event monitor (<code>http://localhost:3000/app/monitor</code>) to see the payloads that are\nreceived when a subscription fires, and then go to store001\n(<code>http://localhost:3000/app/store/urn:ngsi-ld:Building:store001</code>) and buy beer until less than 10 items are in stock.\nThe low stock message should be displayed on screen.</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/low-stock-warehouse.png\" alt=\"low-stock\" /></p>\n<p><code>low-stock-store001</code> is fired when the Products on the shelves within Store001 are getting low, the subscription payload\ncan be seen below:</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/low-stock-monitor.png\" alt=\"low-stock-json\" /></p>\n<p>The data within the payload consists of key-value pairs of the attributes which were specified in the request. This is\nbecause the subscription was created using the <code>format=keyValues</code> attribute. The <code>@context</code> is not present in the\npayload body since <code>endpoint.accept=application/json</code> was set. The effect is to return a <code>data</code> array in a very similar\nformat to the <code>v2/subscription/</code> payload. In addition to the <code>data</code> array, the <code>subscriptionId</code> is included in the\nresponse, along with a <code>notifiedAt</code> element which describes when the notification was fired.</p>\n<p>Now go to store002 (<code>http://localhost:3000/app/store/urn:ngsi-ld:Building:store002</code>) and buy beer until fewer than 10\nitems are in stock. The low stock message is once again displayed on screen, the payload can be seen within the event\nmonitor.</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/low-stock-monitor-ld.png\" alt=\"low-stock-ld\" /></p>\n<p>The second subscription has been set up to pass the full normalized NGSI-LD payload along with the <code>@context</code>. This has\nbeen achieved by using the using the <code>format=normalized</code> attribute within the subscription itself, as well as setting\n<code>endpoint.accept=application/ld+json</code>, so that the <code>@context</code> is also passed with each entity.</p>\n","_postman_id":"1cba4850-92d1-4d50-88f4-47e905f18bd1"},{"name":"Using Registrations with NGSI-LD","item":[{"name":"Create a registration","id":"fddd7191-fbde-46c8-9f1e-5b4cd1da6e56","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json","type":"text"},{"key":"Link","value":"<http://context/ngsi-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"}],"body":{"mode":"raw","raw":"{\n    \"type\": \"ContextSourceRegistration\",\n    \"information\": [\n        {\n            \"entities\": [\n                {\n                    \"type\": \"Building\",\n                    \"id\": \"urn:ngsi-ld:Building:store001\"\n                }\n            ],\n            \"propertyNames\": [\n                \"tweets\"\n            ]\n        }\n    ],\n    \"contextSourceInfo\": [\n        {\n            \"key\": \"jsonldContext\",\n            \"value\": \"http://context/user-context.jsonld\"\n        }\n    ],\n    \"mode\": \"exclusive\",\n    \"operations\": [\n        \"updateOps\",\n        \"retrieveOps\"\n    ],\n    \"endpoint\": \"http://tutorial:3000/static/tweets\"\n}"},"url":"http://localhost:1026/ngsi-ld/v1/csourceRegistrations/","description":"<p>All NGSI-LD Context Provider Registration actions take place on the <code>/ngsi-ld/v1/csourceRegistrations/</code> endpoint. The<br />standard CRUD mappings apply. The <code>@context</code> must be passed either as a <code>Link</code> header or within the main body of the<br />request.</p>\n<p>The body of the request is similar to the <strong>NGSI-v2</strong> equivalent with the following modifications:</p>\n<ul>\n<li>The <strong>NGSI-v2</strong> <code>dataProvided</code> object is now an array called <code>information</code>.</li>\n<li><strong>NGSI-v2</strong> <code>attrs</code> have been split into separate arrays of <code>propertyNames</code> and <code>relationshipNames</code></li>\n<li>The <strong>NGSI-v2</strong> <code>provider.url</code> has moved up to <code>endpoint</code></li>\n<li>The <strong>NGSI-LD</strong> <code>mode</code> and <code>operations</code> are now required - if they are missing the defaults are <code>federationOps</code> and<br />  <code>inclusive</code> which does not match the default <strong>NGSI-v2</strong> <code>supportedForwardingMode</code></li>\n</ul>\n<p><code>contextSourceInfo</code> usually defines additional HTTP Headers which are passed to the registrant, but <code>jsonldContext</code> is a<br />special key which fires a JSON-LD expansion/compaction operation to ensure that the attribute names within the request<br />match the expected <strong>NGSI-v2</strong> attribute names.</p>\n<blockquote>\n<p><strong>Note</strong> that <code>propertyNames</code> and <code>relationshipNames</code> have replaced the older <code>properties</code> attribute that was is<br />defined in the 1.1.1 NGSI-LD core context. It was replaced in order to offer full GeoJSON-LD support. Your context<br />broker may or may not support the updated core context</p>\n</blockquote>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","csourceRegistrations",""],"host":["localhost:1026"],"query":[],"variable":[]}},"response":[],"_postman_id":"fddd7191-fbde-46c8-9f1e-5b4cd1da6e56"},{"name":"Check the registration","id":"d9b3a660-77d9-4ddf-974a-36061c795703","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Accept","value":"application/ld+json","type":"text"},{"key":"Link","value":"<http://context/user-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"}],"url":"http://localhost:1026/ngsi-ld/v1/csourceRegistrations/?type=Building","description":"<p>Retrieving the registration details can be made by sending a GET request to the <code>/ngsi-ld/v1/csourceRegistrations/</code>\nendpoint, along with an appropriate JSON-LD context in the <code>Link</code> header.</p>\n<p>The response returns the details of the registration. In this case the short names of the <code>properties</code> have been\nreturned, along with the <code>@context</code>.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","csourceRegistrations",""],"host":["localhost:1026"],"query":[{"key":"type","value":"Building"}],"variable":[]}},"response":[],"_postman_id":"d9b3a660-77d9-4ddf-974a-36061c795703"},{"name":"Read from Store 1","id":"f0f85746-396e-4b41-9a5d-8542593a15ca","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<http://context/user-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"}],"url":"http://localhost:1026/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001","description":"<p>Once a registration has been set up, the additional registered <code>properties</code> and <code>relationships</code> are transparently\nreturned when an requested entity is requested. For simple registrations, a request to obtain the whole entity will be\nproxied to the registered <code>endpoint</code>, for partial registrations the <code>properties</code> and <code>relationships</code> are added to the\nexisting entity held within the context broker.</p>\n<p>The response now holds an additional <code>tweets</code> Property, which returns the values obtained from\n<code>http://context-provider:3000/static/tweets/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001</code> - i.e. the forwarding\nendpoint.</p>\n<p>The same response data can be seen within the supermarket application itself. In practice this data has been created via\na series of requests - the context broker is responsible for the <code>urn:ngsi-ld:Building:store001</code> data, however it checks\nto see if any further information can be provided from other sources. In our case the <code>CSourceRegistration</code> indicates\nthat one further attribute <em>may</em> be available. The broker then requests <code>tweets</code> information from the context provider,\nand provided that it responds in a timely manner, the <code>tweets</code> information is added to the resultant payload.</p>\n<p>The supermarket application displays the received data on screen within the supermarket application itself:</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/tweets-1.png\" alt=\"tweets-1\" /></p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"f0f85746-396e-4b41-9a5d-8542593a15ca"},{"name":"Read direct from Context Provider","id":"753b430d-b7e5-4658-b411-58482f4afbcd","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<http://context/user-context.jsonld>; rel=\"http://www.w3.org/ns/json-ld#context\"; type=\"application/ld+json\"","type":"text"},{"key":"Content-Type","value":"application/ld+json","type":"text"}],"url":"http://localhost:3000/static/tweets/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001?attrs=tweets","description":"<p>Every context-provider must stand by a fixed contract. At a minimum must be able to respond to varieties of the\n<code>/ngsi-ld/v1/entities/&lt;entity-id&gt;</code> GET request. If the registration is limited to certain properties, this request will\nalso contain an <code>attrs</code> parameter in the query string.</p>\n<p>Dependent upon the use case of the context-provider, it may or may not need to be able to interpret JSON-LD <code>@context</code> -\nin this case a request is merely returning the full <code>tweets</code> attribute.</p>\n<p>The same request is made by the context broker itself when querying for registered attributes</p>\n<p>As can be seen the <code>@context</code> has been returned in the request (since the <code>Content-Type</code> header was set). The rest of\nthe response resembles any standard NGSI-LD request.</p>\n","urlObject":{"protocol":"http","path":["static","tweets","ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001"],"host":["localhost:3000"],"query":[{"disabled":true,"key":"options","value":"keyValues"},{"key":"attrs","value":"tweets"}],"variable":[]}},"response":[],"_postman_id":"753b430d-b7e5-4658-b411-58482f4afbcd"},{"name":"Direct Update to Context Provider","id":"318089ce-0c3b-4fbd-9c89-e08c6754e5a9","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PATCH","header":[{"key":"Link","value":"<http://context/user-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","name":"Accept"},{"key":"Accept","value":"application/json"}],"body":{"mode":"raw","raw":"{ \n\t\"tweets\": { \n\t\t\"type\": \"Property\", \n\t\t\"value\": [\n\t\t\t\"Space is big.\",\n\t\t\t\"You just won't believe how vastly, hugely, mind-bogglingly big it is.\",\n\t\t\t\"I mean, you may think it's a long way down the road to the chemist's, but that's just peanuts to space.\"\n\t\t] \n\t} \n}"},"url":"http://localhost:3000/static/tweets/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001/attrs","description":"<p>For a read-write interface it is also possible to amend context data by making a PATCH request to the relevant\n<code>ngsi-ld/v1/entities/&lt;entity-id&gt;/attrs</code> endpoint.</p>\n","urlObject":{"protocol":"http","path":["static","tweets","ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001","attrs"],"host":["localhost:3000"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"318089ce-0c3b-4fbd-9c89-e08c6754e5a9"},{"name":"Read from Store 1","id":"5a27cb10-4b2b-476f-98b2-8cdf78c197b8","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<http://context/user-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"}],"url":"http://localhost:1026/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001","description":"<p>If the regisitered attribute is requested from the context broker, it returns the <em>updated</em> values obtained from\n<code>http://context-provider:3000/static/tweets/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001</code> - i.e. the forwarding\nendpoint.</p>\n<p>This alters the response to match the values updated in the previous PATCH request.</p>\n<p>Since the context provider is responsible for supplying <code>tweets</code> information, changes in the context provider will\nalways be reflected in requests to the context-broker itself. The supermarket application is calling the context broker\nfor context regardless of origin, so the updated <code>tweets</code> data are displayed on screen within the supermarket\napplication itself:</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/tweets-2.png\" alt=\"tweets-2\" /></p>\n<p>The context broker is therefore able to return a complete holistic picture of the current state of the world.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"5a27cb10-4b2b-476f-98b2-8cdf78c197b8"},{"name":"Forwarded Update","id":"019c2990-a792-42d3-a592-2d26fc6ffdf7","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"PATCH","header":[{"key":"Link","value":"<http://context/user-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","name":"Accept"}],"body":{"mode":"raw","raw":"{ \n\t\"type\": \"Property\", \n\t\"value\": [\n\t\t\"This must be Thursday\",\n\t\t\"I never could get the hang of Thursdays.\"\t\n\t] \n} "},"url":"http://localhost:1026/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001/attrs/tweets","description":"<p>A PATCH request to the context broker ( either <code>ngsi-ld/v1/entities/&lt;entity-id&gt;/</code> or\n<code>ngsi-ld/v1/entities/&lt;entity-id&gt;/attrs</code>) will be forwarded to the registered context provider if a registration is\nfound. It is therefore possible to alter the state of a context-provider as a side effect. Of course, not all context\nproviders are necessarily read-write, so attempting to change the attributes of forwarded context may not be fully\nrespected.</p>\n<p>In this case however a request to PATCH <code>ngsi-ld/v1/entities/&lt;entity-id&gt;</code> will be successfully forwarded as a series of\n<code>ngsi-ld/v1/entities/&lt;entity-id&gt;/attrs</code> requests for each regsitered attribute that is found in the registration.</p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001","attrs","tweets"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"019c2990-a792-42d3-a592-2d26fc6ffdf7"},{"name":"Read from Store 1","id":"35e044f3-075f-49ea-b5c2-de3e74d87b55","protocolProfileBehavior":{"disableBodyPruning":true},"request":{"method":"GET","header":[{"key":"Link","value":"<http://context/user-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"}],"url":"http://localhost:1026/ngsi-ld/v1/entities/urn:ngsi-ld:Building:store001","description":"<p>The result of the previous operation can be seen by retrieving the whole entity using a GET request.</p>\n<p>This alters the response to match the values updated in the previous PATCH request which was sent to the context broker\nand then forwarded to the context provider endpoint.</p>\n<p>As can be seen, the updated <code>tweets</code> data is also displayed within the supermarket application itself:</p>\n<p><img src=\"https://fiware.github.io/tutorials.LD-Subscriptions-Registrations/img/tweets-3.png\" alt=\"tweets-3\" /></p>\n","urlObject":{"protocol":"http","path":["ngsi-ld","v1","entities","urn:ngsi-ld:Building:store001"],"host":["localhost:1026"],"query":[{"disabled":true,"key":"options","value":"keyValues"}],"variable":[]}},"response":[],"_postman_id":"35e044f3-075f-49ea-b5c2-de3e74d87b55"}],"id":"7dab7984-3f5e-4c2b-a458-7b0691633d49","description":"<p>Context Registrations allow some (or all) data within an entity to be provided by an external context provider. It could<br />be another full context-provider a separate micro-service which only responds to a subset of the NGSI-LD endpoints.<br />However, there needs to be a contract created as to who supplies what.</p>\n<p>All <strong>NGSI-LD</strong> registrations can be subdivided into one of four types:</p>\n<h3 id=\"additive-registrations\">Additive Registrations</h3>\n<p>A Context Broker is permitted to hold context data about the Entities and Attributes locally itself, and also obtain<br />data from (possibly multiple) external sources</p>\n<ul>\n<li>An <strong>inclusive</strong> Context Source Registration specifies that the Context Broker considers all registered Context<br />  Sources as equals and will distribute operations to those Context Sources even if relevant context data is available<br />  directly within the Context Broker itself (in which case, all results will be integrated in the final response).<br />  This federative and is the default mode of operation.</li>\n<li>An <strong>auxiliary</strong> Context Source Registration never overrides data held directly within a Context Broker. Auxiliary<br />  distributed operations are limited to context information consumption operations (i.e. entity <strong>GET</strong> operations).<br />  Context data from auxiliary context sources is only included if it is supplementary to the context data otherwise<br />  available to the Context Broker.</li>\n</ul>\n<h3 id=\"proxied-registrations\">Proxied Registrations</h3>\n<p>A Context Broker is not permitted to hold context data about the Entities and Attributes locally itself. All context<br />data is obtained from the external registered sources.</p>\n<ul>\n<li>An <strong>exclusive</strong> Context Source Registration specifies that all of the registered context data is held in a single<br />  location external to the Context Broker. The Context Broker itself holds no data locally about the registered<br />  Attributes and no overlapping proxied Context Source Registrations shall be supported for the same combination of<br />  registered Attributes on the Entity. An exclusive registration must be fully specified. It always relates to<br />  specific Attributes found on a single Entity. It can be used for actuations</li>\n<li>A <strong>redirect</strong> Context Source Registration also specifies that the registered context data is held in a location<br />  external to the Context Broker, but potentially multiple distinct redirect registrations can apply at the same time.</li>\n</ul>\n<h3 id=\"accepted-operations\">Accepted Operations</h3>\n<p><strong>NGSI-LD</strong> also defines groups of operations that are allowed on the registrant. The default group is called<br /><code>federationOps</code> and includes all entity <strong>GET</strong> operations. Three other common operational groups are also defined<br /><code>updateOps</code> (for actuators), <code>retrieveOps</code> (for \"lazy\" sensors) and <code>redirectionOps</code> (for hierarchical broker<br />architectures). The details won't be covered here, but it should be noted that unless specified, the default <strong>NGSI-LD</strong><br />operation is <code>federationOps</code> using <code>inclusive</code> mode, whereas the default <strong>NGSI-v2</strong> operation is<br /><code>updateOps + retrieveOps</code> using <code>exclusive</code> mode.</p>\n<p>For simplicity, for <strong>NGSI-v2</strong> - <strong>NGSI-LD</strong> comparison, this tutorial will only deal with <code>exclusive</code> mode, which is<br />the only mode offered by <strong>NGSI-v2</strong> brokers.</p>\n<p>With the <strong>NGSI-LD</strong> <code>exclusive</code> mode, all registrations can be subdivided into one of two types. Simple registrations<br />where a single context provider is responsible for the maintenance of the whole entity, and partial registrations where<br />attributes are spread across multiple context providers. For a simple registration, all context requests are forwarded</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request</th>\n<th>Action at <strong>Context Broker</strong></th>\n<th>Action at <strong>Context Provider</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>GET</strong></td>\n<td>Pass request to <strong>Context Provider</strong>, proxy the response back unaltered.</td>\n<td>Respond to context broker with the result of the GET request based on the entities held internally</td>\n</tr>\n<tr>\n<td><strong>PATCH</strong></td>\n<td>Pass request to <strong>Context Provider</strong>, proxy back the HTTP back status code.</td>\n<td>Update the entity within the <strong>Context Provider</strong>, Respond to the context broker with a status code</td>\n</tr>\n<tr>\n<td><strong>DELETE</strong></td>\n<td>Pass request to <strong>Context Provider</strong></td>\n<td>Delete the entity within the <strong>Context Provider</strong>, Respond to the context broker with a status code</td>\n</tr>\n</tbody>\n</table>\n</div><p>Effectively every simple registration is saying <em>\"this entity is held elsewhere\"</em>, but the entity data can be requested<br />and modified via requests to this context broker.</p>\n<p>For partial registrations the situation is more complex</p>\n<div class=\"click-to-expand-wrapper is-table-wrapper\"><table>\n<thead>\n<tr>\n<th>Request</th>\n<th>Action at <strong>Context Broker</strong></th>\n<th>Action at <strong>Context Provider</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>GET</strong></td>\n<td>Assuming an entity exists locally, pass request for additional proxied attributes to <strong>Context Provider</strong>, concatenate a response back for locally held attributes and additional information from the <strong>Context Provider</strong></td>\n<td>Respond to context broker with the result of the GET request based on the entities held internally</td>\n</tr>\n<tr>\n<td><strong>PATCH</strong></td>\n<td>Update any locally held attributes, Pass update requests for additional attributes to <strong>Context Provider</strong>, and return <strong>success</strong> or <strong>partial success</strong> HTTP status code dependent upon the overall result.</td>\n<td>Update the requested attributes of the entity held within the <strong>Context Provider</strong>. Respond to the context broker with a status code</td>\n</tr>\n<tr>\n<td><strong>DELETE</strong></td>\n<td>If deleting an entity, remove the complete local instance. If deleting locally held attributes remove them. If deleting attributes held in the <strong>Context Provider</strong>, pass request on to <strong>Context Provider</strong></td>\n<td>Delete the entity attributes within the <strong>Context Provider</strong>, Respond to the context broker with a status code</td>\n</tr>\n</tbody>\n</table>\n</div><p>Each partial registration is saying <em>\"additional augmented context for this entity is held elsewhere\"</em>. The entity data<br />can be requested and modified via requests to this context broker.</p>\n<p>With normal operation, the NGSI-LD response does not expose whether data collated from multiple sources is held directly<br />within the context broker or whether the information has been retrieved externally. It is only when an error occurs<br />(e.g. timeout) that the HTTP status error code reveals that externally held information could not be retrieved or<br />amended.</p>\n","event":[{"listen":"prerequest","script":{"id":"d40ce400-5e95-4581-a9ff-7c78aca6372c","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"67202d76-f388-48b5-9f15-cea8468a6f1c","type":"text/javascript","exec":[""]}}],"_postman_id":"7dab7984-3f5e-4c2b-a458-7b0691633d49"}],"event":[{"listen":"prerequest","script":{"id":"8c2c41f3-896d-49c5-9da4-2c73a3adc41c","type":"text/javascript","exec":[""]}},{"listen":"test","script":{"id":"bb19d09c-a946-4b85-927a-1b30054a68bd","type":"text/javascript","exec":[""]}}],"variable":[{"key":"context-broker","value":"localhost:1026"},{"key":"datamodels-context.jsonld","value":"http://context/user-context.jsonld"},{"key":"context-provider","value":"localhost:3000"}]}