Skip to main content

Using NGSI-LD API

Documentation Update

Garnet Framework has evolved with architectural improvements for better cost efficiency and scalability. This documentation is current and reflects these changes, though we continue to expand certain sections with additional examples and detailed guidance.

Thank you for your patience as we complete this update.

The NGSI-LD API provides a comprehensive set of operations to build and manage your knowledge graph. This section offers practical examples to help you understand how to use the API effectively. For a complete reference of all API capabilities and advanced usage patterns, refer to the Deep Dive section.

If you are not familiar with the NGSI-LD specification, we recommend reading the Understanding NGSI-LD section first for a better conceptual foundation.

Accessing Your NGSI-LD API

When working with the NGSI-LD API in Garnet Framework, you'll use the endpoint and authentication token provided during deployment. For subscriptions, you have two notification delivery options. These can be found in your CloudFormation outputs:

  • GarnetEndpoint: Your API endpoint for NGSI-LD operations
  • GarnetApiToken: The authentication token for API access
  • GarnetPrivateSubEndpoint: Your Garnet Private Notification Endpoint for Secured Subscriptions (alternatively, you can use the simplified garnet:notification approach)

You can verify your API is ready by opening the GarnetEndpoint URL in your browser, which should return information about your deployment including version, architecture, and available services.

Throughout this guide, each API operation is presented in two formats:

  • An API Call tab showing the basic request structure for conceptual understanding
  • A curl tab providing a complete, ready-to-use command

This approach allows you to focus on understanding the concepts while having practical examples ready for implementation.

Tools for API Interaction

While you can use curl commands directly, there are various API development tools available that you can use depending on your preferences. We are currently working on providing a Postman collection to help you get started quickly.

For command line operations, you can store your credentials as environment variables. When setting GARNET_ENDPOINT, ensure the URL does not end with a forward slash /:

export GARNET_ENDPOINT=<Your GarnetEndpoint>
export GARNET_TOKEN=<Your GarnetApiToken>
export GARNET_PRIVATE_SUB_ENDPOINT=<Your GarnetPrivateSubEndpoint>

Verifying Your API Access

After setting up your development environment with the appropriate tools, let's verify that your API is responding correctly by checking what types exist in your knowledge graph:

GET Types
GET /ngsi-ld/v1/types
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This should return an empty type list as we haven't created any entities yet.

{
"id" : "urn:ngsi-ld:EntityTypeList:1",
"type" : "EntityTypeList",
"ngsi-ld:typeList" : [ ]
}

We'll explore this endpoint in detail in the Knowledge Graph Discovery section.

Building Your Knowledge Graph

The NGSI-LD API enables you to build rich knowledge graphs representing real-world entities and their relationships.

The NGSI-LD API provides several interfaces for managing your knowledge graph. The main interfaces we'll explore are:

  • /ngsi-ld/v1/entities: Core interface for individual entity operations
    • Create, retrieve, update, and delete entities
    • Query entities with filtering and pagination
    • Manage entity attributes
  • /ngsi-ld/v1/entityOperations: Interface for batch operations
    • Create, update, or delete multiple entities efficiently
    • Perform operations on groups of entities in a single request
NGSI-LD API Swagger documentation

For a complete reference of all available endpoints and operations, see the NGSI-LD API Swagger documentation

Let's build a smart building scenario that demonstrates key NGSI-LD concepts and capabilities.

Creating Your First Entity

Let's start with a simple building entity that demonstrates fundamental NGSI-LD concepts:

{
"id": "urn:ngsi-ld:Building:Office-1",
"type": ["Building", "Office"],
"name": {
"type": "Property",
"value": "Office 1"
},
"address": {
"type": "Property",
"value": {
"streetAddress": "60 Holborn Viaduct",
"addressLocality": "London",
"postalCode": "EC1A 2FD"
}
},
"hasTenant": {
"type": "Relationship",
"object": "urn:ngsi-ld:Organization:BayaCorp",
"objectType": "Organization",
"contract": {
"type": "Relationship",
"object": "urn:ngsi-ld:LeaseAgreement:Lease-BayaCorp-20231105",
"objectType": "LeaseAgreement",
"startDate": {
"type": "Property",
"value": "2023-11-05T00:00:00Z"
}
}
},
"scope": "/Region/Europe/Country/UK/City/London"
}

This entity demonstrates several fundamental NGSI-LD concepts:

Entity Identification

Every entity in NGSI-LD must have a unique identifier. The id field uses a URN format that combines the entity type with a unique identifier. For our building, urn:ngsi-ld:Building:Office-1 indicates this is a Building entity with identifier "Office-1". When using multi-typing, the type used in the URN should be the primary or most descriptive type for the entity. This structured approach to identification helps prevent conflicts and makes entity references clear and consistent across your knowledge graph.

Multi-typing

NGSI-LD allows entities to have multiple types, specified as an array in the type field. Our building is both a Building and an Office, enabling flexible categorization and querying patterns. Applications can search broadly for any Building or specifically for Office entities, allowing different levels of specificity in queries, data consumption, and subscriptions that we will explore later.

NGSI-LD Properties

Properties in NGSI-LD represent information about an entity through structured attributes. Each property includes a type: "Property" declaration and a value field containing the actual data.

Properties can contain simple values, like text or numbers, complex structured data, or arrays of values (though order is not preserved). When order matters, NGSI-LD provides the specific ListProperty type, covered in later examples. Properties can also include their own metadata, enabling rich descriptions of how and when values were obtained.

NGSI-LD Relationships

Relationships represent connections between entities using the type: "Relationship" declaration. Each relationship requires:

  • An object field containing the URI of the related entity
  • An objectType field specifying the expected type of the referenced entity

The object field can contain a single URI or an array of URIs (though order is not preserved). When the order of relationships matters, NGSI-LD provides the specific ListRelationship type, covered in later examples.

In our example, the hasTenant relationship connects the building to an organization - urn:ngsi-ld:Organization:BayaCorp - which can be retrieved in a single query through graph traversal (covered later in the documentation). The nested contract relationship provides a reference to the specific lease agreement, allowing applications to access detailed contractual information when needed.

Scopes

NGSI-LD scopes enable organizing entities in hierarchical structures through the scope field.

In our example, /Region/Europe/Country/UK/City/London creates a hierarchical categorization for the building. An entity can belong to multiple hierarchies by providing an array of scopes, enabling diverse access patterns and organizational structures.

Querying becomes powerful with wildcards: /Region/Europe/Country/UK/City/+ would match entities in all UK cities, while /Region/Europe/# would match all European entities at any level below.

NGSI-LD Context

Building on JSON-LD's semantic foundation, NGSI-LD uses contexts to map terms to IRIs (Internationalized Resource Identifiers), enabling semantic interoperability across systems. In this example, we're using the default NGSI-LD core context as no @context attribute is specified. You can use existing data models, like those from the Smart Data Models initiative, or define your own contexts based on your needs.

For a detailed explanation of how contexts work and how they enable semantic interoperability, refer to the JSON-LD Context section in the Understanding NGSI-LD page.

To create this entity, we'll use the /ngsi-ld/v1/entities endpoint with a POST request. The request body contains our entity definition as shown above.

Note that if the entity includes an @context attribute, the Content-Type must be application/ld+json.

POST Entity
POST /ngsi-ld/v1/entities
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body:
{entity}

Entity Management Operations

In addition to creating entities with the POST operation we just used, the NGSI-LD API provides standard REST operations for updating and deleting both entities and their attributes:

  • PUT /ngsi-ld/v1/entities/{entityId} - Replace entire entity
  • PATCH /ngsi-ld/v1/entities/{entityId}/attrs - Add or update specific attributes
  • DELETE /ngsi-ld/v1/entities/{entityId} - Remove an entity

Let's add geographic coordinates to our building to enable spatial queries and geographic analysis:

{
"location": {
"type": "GeoProperty",
"value": {
"type": "Point",
"coordinates": [-0.104049, 51.517417]
}
}
}

GeoProperties

NGSI-LD represents geographical information using the GeoProperty type with GeoJSON format. Each GeoProperty requires a value containing a GeoJSON geometry object. In our example, we're using a Point geometry with coordinates in [longitude, latitude] format. This standardized representation enables powerful geospatial queries, which we'll explore later.

Beyond simple points, GeoJSON supports other geometry types like LineStrings for routes, Polygons for areas, and MultiPolygons for complex regions. This flexibility enables sophisticated spatial queries such as finding entities within specific areas or calculating distances between locations.

To add this location information to our existing building, we'll use the PATCH operation on the /ngsi-ld/v1/entities/{entityId}/attrs endpoint. This endpoint allows us to add or update specific attributes without modifying the entire entity.

PATCH Entity Attributes
PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:Building:Office-1/attrs
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body:
{Entity Attributes}

Batch Operations

NGSI-LD provides efficient batch operations through the /ngsi-ld/v1/entityOperations endpoint for managing multiple entities simultaneously.

Batch Entity Creation

The batch creation operation allows creating multiple entities in a single request using an array of entity definitions. If some entities already exist, the operation will partially succeed - creating new entities while skipping existing ones. The response will indicate which entities were successfully created and which ones failed.

In our example, we'll create four entities:

  • Two rooms with temperature measurements, each linked to our building through the inBuilding relationship
  • Two indoor air quality sensors, each placed in one of the rooms through the inSpace relationship
[
{
"id": "urn:ngsi-ld:Room:Room-101",
"type": "Room",
"name": {
"type": "Property",
"value": "Room-101"
},
"temperature": {
"type": "Property",
"value": 21.7,
"unitCode": "CEL",
"observedAt": "2025-02-23T12:00:00Z"
},
"inBuilding": {
"type": "Relationship",
"object": "urn:ngsi-ld:Building:Office-1",
"objectType": "Building"
},
"scope": [
"/building/Office-1/floor/floor01/room/Room-101"
]
},
{
"id": "urn:ngsi-ld:Room:Room-201",
"type": "Room",
"name": {
"type": "Property",
"value": "Room-201"
},
"temperature": {
"type": "Property",
"value": 22.3,
"unitCode": "CEL",
"observedAt": "2025-02-23T08:00:00Z"
},
"inBuilding": {
"type": "Relationship",
"object": "urn:ngsi-ld:Building:Office-1",
"objectType": "Building"
},
"scope": [
"/building/Office-1/floor/floor02/room/Room-201"
]
},
{
"id": "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001",
"type": [
"IndoorAirQualitySensor",
"AirQualitySensor",
"Sensor"
],
"inSpace": {
"type": "Relationship",
"object": "urn:ngsi-ld:Room:Room-101"
}
},
{
"id": "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-002",
"type": [
"IndoorAirQualitySensor",
"AirQualitySensor",
"Sensor"
],
"inSpace": {
"type": "Relationship",
"object": "urn:ngsi-ld:Room:Room-201"
}
}
]

To create these entities, we'll use the /ngsi-ld/v1/entityOperations/create endpoint with a POST request. The request body should contain an array of entity definitions. The operation will attempt to create all entities and return a success or failure status for each one. If an entity already exists, the creation for that specific entity will fail, but this won't affect the creation of other entities in the batch.

POST Batch Create
POST /ngsi-ld/v1/entityOperations/create 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: [{entities}]

The response includes successful and failed operations:

{
"success": [
"urn:ngsi-ld:Room:Room-101",
"urn:ngsi-ld:Room:Room-201",
"urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001",
"urn:ngsi-ld:AirQualityIndoorSensor:AIQ-002"
],
"errors": []
}

Now that we have our initial entities created, let's explore how to update them in batch using the upsert operation, which offers more flexibility by allowing both creation and updates in a single request.

Batch Update and Upsert Operations

NGSI-LD offers two approaches for modifying multiple entities:

  • The update operation /entityOperations/update which only works with existing entities and removes attributes not included in the payload
  • The upsert operation /entityOperations/upsert which can both create new entities and update existing ones

We'll use the upsert operation as it provides more flexibility, allowing us to update our existing room's temperature while also adding a new sensor. By default, upsert completely overwrites existing entities, removing any attributes not included in the payload. However, when used with options=update, it preserves existing attributes while updating only those provided in the request.

Let's update temperature readings at different times and add a new occupancy sensor:

[
{
"id": "urn:ngsi-ld:Room:Room-101",
"type": ["Room", "MeetingRoom"],
"temperature": {
"type": "Property",
"value": 23.1,
"unitCode": "CEL",
"observedAt": "2025-02-23T12:30:00Z",
"measuredBy": {
"object": "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
}
}
},
{
"id": "urn:ngsi-ld:Room:Room-101",
"type": ["Room", "MeetingRoom"],
"temperature": {
"type": "Property",
"value": 23.8,
"unitCode": "CEL",
"observedAt": "2025-02-23T12:45:00Z",
"measuredBy": {
"object": "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
}
}
},
{
"id": "urn:ngsi-ld:OccupancySensor:OCC-001",
"type": [
"OccupancySensor",
"Sensor"
],
"inSpace": {
"type": "Relationship",
"object": "urn:ngsi-ld:Room:Room-101"
}
}
]

To process these updates, we'll use the /ngsi-ld/v1/entityOperations/upsert endpoint with a POST request. We'll include the options=update parameter to preserve existing attributes while updating only those provided in the payload:

POST Batch Upsert
POST /ngsi-ld/v1/entityOperations/upsert?options=update 
Headers:
'Authorization': {GARNET_TOKEN}
'Content-Type': 'application/json'
Body: [{entities}]

The response shows all operations succeeded with an array of created entities:

[
"urn:ngsi-ld:OccupancySensor:OCC-001"
]

By providing two temperature updates for Room-101 with different observedAt timestamps in our upsert operation, we've not only updated the current state but also created a temporal history. When attributes include temporal properties like observedAt, NGSI-LD automatically maintains their historical values, enabling you to track how entity attributes evolve over time. This temporal capability will be explored in detail later in this guide.

Batch Entity Deletion

NGSI-LD also supports batch deletion operations through the /ngsi-ld/v1/entityOperations/delete endpoint. You can delete multiple entities by providing an array of entity IDs. This operation is useful for cleanup operations or removing groups of related entities.

info

The following example demonstrates batch deletion syntax but should not be executed if you want to continue following the rest of this guide, as it would remove the entities we've created for subsequent examples.

POST Batch Delete
POST /ngsi-ld/v1/entityOperations/delete
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: [
"urn:ngsi-ld:Room:Room-101",
"urn:ngsi-ld:Room:Room-201",
"urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
]

The operation returns a response indicating which entities were successfully deleted and which operations failed:

{
"success": [
"urn:ngsi-ld:Room:Room-101",
"urn:ngsi-ld:Room:Room-201",
"urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
],
"errors": []
}

Now that we've built our knowledge graph with entities, relationships, and temporal data, let's explore how to discover and query the information we've created. The NGSI-LD API provides comprehensive capabilities for understanding what data exists in your knowledge graph and retrieving it in various ways.

Exploring Your Knowledge Graph

The NGSI-LD API provides multiple ways to explore and consume the information stored in your knowledge graph. From discovering available entity types to specialized queries for temporal history or geographic location, these capabilities enable you to extract meaningful insights from your context information in different dimensions.

Knowledge Graph Discovery

Understanding what information exists in your knowledge graph is essential for both applications and users. The discovery mechanisms help applications understand the structure of the knowledge graph, particularly valuable for autonomous agents or dynamic applications that need to adapt to available context information.

Understanding Available Types

The Types interface enables you to discover what kinds of entities exist in your knowledge graph and how they're structured. Let's start by exploring the available entity types:

GET Types
GET /ngsi-ld/v1/types
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This returns an array of available types in your knowledge graph. For our smart building example, you might see:

{
"id": "urn:ngsi-ld:EntityTypeList:205825319",
"type": "EntityTypeList",
"typeList" : [
"MeetingRoom",
"Office",
"Room",
"Building",
"OccupancySensor",
"Sensor",
"AirQualitySensor",
"IndoorAirQualitySensor"
]
}

To get detailed information about a specific type, including its attributes and their types:

GET Type Info
GET /ngsi-ld/v1/types/{type}
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This provides detailed information about the Building type:

{
"id" : "ngsi-ld:default-context/Building",
"type" : "EntityTypeInfo",
"attributeDetails" : [ {
"id" : "ngsi-ld:default-context/address",
"attributeName" : "address",
"attributeTypes" : [ "Property" ],
"type" : "Attribute"
}, {
"id" : "ngsi-ld:default-context/hasTenant",
"attributeName" : "hasTenant",
"attributeTypes" : [ "Relationship" ],
"type" : "Attribute"
}, {
"id" : "ngsi-ld:default-context/name",
"attributeName" : "name",
"attributeTypes" : [ "Property" ],
"type" : "Attribute"
}, {
"id" : "location",
"attributeName" : "location",
"attributeTypes" : [ "GeoProperty" ],
"type" : "Attribute"
}, {
"id" : "scope",
"attributeName" : "scope",
"attributeTypes" : [ null ],
"type" : "Attribute"
} ],
"entityCount" : 1,
"typeName" : "Building"
}

Exploring Available Attributes

Similarly, you can discover all attributes used across your knowledge graph:

GET Attributes
GET /ngsi-ld/v1/attributes 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

For details about a specific attribute:

GET Attribute Info
GET /ngsi-ld/v1/attributes/{attributeId} 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This discovery capability helps applications understand what information is available and how it's structured, enabling more dynamic and adaptable behaviors. For example, a dashboard application could automatically adjust its display based on available entity types and attributes, or an AI agent could understand what context information it can access and monitor.

Basic Entity Queries

After discovering what types and attributes exist in your knowledge graph, let's explore how to retrieve entities. The /ngsi-ld/v1/entities endpoint with GET method enables retrieving both individual entities and collections of entities based on various criteria.

To retrieve a specific entity, use /ngsi-ld/v1/entities/{entityId}. By default, this returns the entity in normalized NGSI-LD format:

GET Entity
GET /ngsi-ld/v1/entities/{entityId} 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

Response Representations

NGSI-LD provides three ways to represent entity data, controlled through the options parameter:

Normalized Representation (Default)

The normalized representation provides complete metadata about properties and relationships. This is the default format when no options are specified:

{
"id": "urn:ngsi-ld:Building:Office-1",
"type": ["Building", "Office"],
"name": {
"type": "Property",
"value": "Office 1"
},
"location": {
"type": "GeoProperty",
"value": {
"type": "Point",
"coordinates": [-0.104049, 51.517417]
}
}
}

The concise representation simplifies the format by removing the type declarations from Properties and Relationships. Use this format by adding options=concise to your query:

GET Entity Concise
GET /ngsi-ld/v1/entities/{entityId}?options=concise 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

The response omits the type declarations while preserving the essential structure:

{
"id": "urn:ngsi-ld:Building:Office-1",
"type": ["Building", "Office"],
"name": "Office 1",
"location": {
"value": {
"type": "Point",
"coordinates": [-0.104049, 51.517417]
}
}
}
Simplified Representation

For cases where only the values are needed, use options=simplified (or options=keyValues). This format removes both type information and the value wrapper, providing the most compact representation:

GET Entity Simplified
GET /ngsi-ld/v1/entities/{entityId}?options=simplified 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

The simplified response contains just the values:

{
"id": "urn:ngsi-ld:Building:Office-1",
"type": ["Building", "Office"],
"name": "Office 1",
"location": {
"type": "Point",
"coordinates": [-0.104049, 51.517417]
}
}

Query Parameters

The /ngsi-ld/v1/entities endpoint supports several parameters to customize your queries:

Filtering Attributes

NGSI-LD provides two mutually exclusive parameters for filtering which elements to include or exclude from the response:

The pick parameter specifies which attributes and elements to include:

GET Entity Pick Attributes
GET /ngsi-ld/v1/entities/{entityId}?pick=id,name
Headers: 'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

The response includes only the specified attributes:

{
"id": "urn:ngsi-ld:Building:Office-1",
"name": {
"value": "Office 1"
}
}

Alternatively, use the omit parameter to exclude specific attributes while returning all others:

GET Entity Omit Attributes
GET /ngsi-ld/v1/entities/{entityId}?omit=hasTenant 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
info

When omitting or not picking "id" and/or "type", the result will not contain valid NGSI-LD Entities and cannot be used as the basis for subsequent NGSI-LD operations.

System-Generated Metadata

Include creation and modification timestamps by adding sysAttrs to the options:

GET Entity System Attributes
GET /ngsi-ld/v1/entities/{entityId}?options=concise,sysAttrs 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

The response includes system-generated timestamps:

{
"id": "urn:ngsi-ld:Building:Office-1",
"type": ["Building", "Office"],
"name": {
"value": "Office 1",
"createdAt": "2025-05-01T12:00:00Z",
"modifiedAt": "2025-05-01T12:00:00Z"
},
"createdAt": "2025-05-01T12:00:00Z",
"modifiedAt": "2025-05-01T12:00:00Z"
}

Querying Multiple Entities

The /ngsi-ld/v1/entities endpoint enables retrieving collections of entities based on various criteria. One of the most powerful filtering mechanisms is querying by entity type, which leverages the categorization capabilities we explored when creating entities.

Type-based Filtering

Remember how we used multiple types to categorize our rooms as both "Room" and "MeetingRoom"? This multi-typing enables flexible querying patterns. You can retrieve entities by any of their types:

GET Entities by Type
GET /ngsi-ld/v1/entities?type=Room
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query returns all entities of type Room, regardless of any additional types they might have:

[ 
{
"id" : "urn:ngsi-ld:Room:Room-101",
"type" : "Room",
"inBuilding" : {
"type" : "Relationship",
"object" : "urn:ngsi-ld:Building:Office-1",
"objectType": "Building"
},
"name" : {
"type" : "Property",
"value" : "Room-101"
},
"temperature" : {
"type" : "Property",
"value" : 21.7,
"observedAt" : "2024-02-23T12:00:00Z",
"unitCode" : {
"type" : "Property",
"value" : "CEL"
}
}
}, {
"id" : "urn:ngsi-ld:Room:Room-201",
"type" : "Room",
"inBuilding" : {
"type" : "Relationship",
"object" : "urn:ngsi-ld:Building:Office-1",
"objectType": "Building"
},
"name" : {
"type" : "Property",
"value" : "Room-201"
},
"temperature" : {
"type" : "Property",
"value" : 22.3,
"observedAt" : "2024-02-23T12:00:00Z",
"unitCode" : {
"type" : "Property",
"value" : "CEL"
}
}
}
]

You can also query for multiple types simultaneously by providing a comma-separated list:

GET Entities Multiple Types
GET /ngsi-ld/v1/entities?type=Room,Sensor
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query returns entities that have either type "Room" OR type "Sensor", enabling you to retrieve different categories of entities in a single request.

important

When querying entities, you must always specify at least one filtering criterion. This can be:

  • A type using the type parameter
  • A query condition using the q parameter
  • A list of attributes using pick or omit

Additional Filtering Mechanisms

Beyond type-based filtering, NGSI-LD provides powerful query capabilities through the q parameter. Let's explore these filtering options using our smart building entities:

Query Patterns

The q parameter supports various comparison operators and can combine multiple conditions. For example, to find rooms with temperature above 23 degrees:

GET Entities with Query
GET /ngsi-ld/v1/entities?type=Room&q=temperature>23
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
info

When using special characters like > in query parameters, make sure to URL-encode them (for example, use %3E instead of >) to ensure your queries work correctly.

You can combine multiple conditions using semicolons. For example, to find all rooms in a specific building with high temperatures:

GET Entities Complex Query
GET /ngsi-ld/v1/entities?type=Room&q=temperature>23;inBuilding=="urn:ngsi-ld:Building:Office-1"
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

Pattern Matching

NGSI-LD supports pattern matching using regular expressions with the ~= operator. For example, to find all rooms with names starting with "Room-":

GET Entities Pattern Match
GET /ngsi-ld/v1/entities?type=Room&q=name~="Room-.*"
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

You can create more sophisticated patterns, like finding room numbered either 2 or 3:

GET Entities Complex Pattern
GET /ngsi-ld/v1/entities?type=Room&q=name~="Room-[23].*"
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query will match Room entities whose name attribute starts with “Room-2” or “Room-3”.

Query Language Capabilities

The NGSI-LD Query Language offers sophisticated filtering capabilities through the q parameter. Let's explore some advanced patterns:

Logical Operators

Combine conditions using OR (|) and check for attribute existence:

Query Examples
// Rooms with temperature above 23°C OR occupancy above 5 persons
q=(temperature>23|occupancy>5)

// Rooms with CO2 levels above 1000 PPM AND humidity below 30%
q=co2>1000;humidity<30
Complex Range Conditions

Create range queries by combining multiple conditions:

Range Query
// Rooms with temperature between 20-25°C OR occupancy of 10 persons or less
q=(temperature>=20;temperature<=25)|occupancy<=10
Attribute Path Traversal

Query nested properties and temporal metadata using dot notation:

GET Entities Attribute Path
GET /ngsi-ld/v1/entities?type=Room&q=temperature.observedAt>=2024-02-23T12:10:00Z
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query finds rooms with temperature measurements taken after a specific timestamp.

Additional query capabilities include:

  • Pattern matching with regular expressions: q=name~="Room-[12].*"
  • Using POSIX character classes: q=name~="Sensor[[:alnum:]]+$"
  • Querying nested properties: q=address[addressLocality]=="London"
  • Combining multiple conditions: q=temperature>23;occupancy>0
tip

These examples demonstrate common query patterns, but the NGSI-LD Query Language offers many more capabilities. For a complete reference of all query features and operators, refer to the Deep Dive section.

Scope-based Filtering

NGSI-LD scopes enable hierarchical filtering of entities. Remember how we created our rooms with scopes like /building/Office-1/floor/floor01/room/Room-101? We can use these hierarchies to filter entities efficiently:

GET Entities by Scope
GET /ngsi-ld/v1/entities?type=Room&scopeQ=/building/Office-1/floor/floor01/#
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query uses scope wildcards:

  • The # wildcard matches all levels below the specified path
  • The + wildcard matches exactly one level

For example:

  • /building/Office-1/floor/+/room/+ matches rooms on any floor in Office-1
  • /building/Office-1/floor/floor01/# matches everything on floor01
  • /building/Office-1/# matches everything in Office-1

You can combine scope filtering with other query parameters for precise entity selection:

GET Entities Complex Scope
GET /ngsi-ld/v1/entities?type=Room&scope=/building/Office-1/floor/floor01/#&q=temperature>23 
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query finds all rooms on floor01 with temperatures above 23°C, demonstrating how scopes can be combined with attribute filters for powerful querying capabilities.

Retrieving Linked Entities

While queries we have seen so far allow you to retrieve individual entities, NGSI-LD also provides sophisticated capabilities for traversing relationships between entities. This enables you to retrieve not just a single entity, but also its connected entities in a single request, making it easier to understand the full context of your data.

To retrieve linked entities, you need to ensure your relationships include the objectType attribute, specifying the type of the target entity. The retrieval is controlled through two parameters:

  • join: Specifies the representation format (inline or flat)
  • joinLevel: Controls how many levels of relationships to traverse (default is 1)

The joinLevel parameter helps prevent excessive cascading when traversing relationships, ensuring efficient queries. Let's explore both representation formats using our smart building example.

Inline Representation

The inline representation embeds linked entities within their respective relationships, maintaining the hierarchical structure of your data. This is particularly useful when you need to preserve the relationship context in your application.

GET Entity with Inline Links
GET /ngsi-ld/v1/entities/urn:ngsi-ld:Room:Room-101?join=inline&joinLevel=1
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

In the response below, notice how the building information is nested within the inBuilding relationship, making it easy to understand the connection between entities:

{
"id" : "urn:ngsi-ld:Room:Room-101",
"type" : [ "MeetingRoom", "Room" ],
"inBuilding" : {
"type" : "Relationship",
"entity" : {
"id" : "urn:ngsi-ld:Building:Office-1",
"type" : [ "Building", "Office" ],
"address" : {
"type" : "Property",
"value" : {
"addressLocality" : "London",
"postalCode" : "EC1A 2FD",
"streetAddress" : "60 Holborn Viaduct"
}
},
"hasTenant" : {
"type" : "Relationship",
"contract" : {
"type" : "Relationship",
"startDate" : {
"type" : "Property",
"value" : "2023-11-05T00:00:00Z"
},
"object" : "urn:ngsi-ld:LeaseAgreement:Lease-BayaCorp-20231105",
"objectType" : "LeaseAgreement"
},
"object" : "urn:ngsi-ld:Organization:BayaCorp",
"objectType" : "Organization"
},
"name" : {
"type" : "Property",
"value" : "Office 1"
},
"location" : {
"type" : "GeoProperty",
"value" : {
"type" : "Point",
"coordinates" : [ -0.104049, 51.517417 ]
}
},
"scope" : "/Region/Europe/Country/UK/City/London"
},
"object" : "urn:ngsi-ld:Building:Office-1",
"objectType" : "Building"
},
"name" : {
"type" : "Property",
"value" : "Room-101"
},
"temperature" : {
"type" : "Property",
"value" : 23.8,
"observedAt" : "2024-02-23T12:45:00Z",
"unitCode" : {
"type" : "Property",
"value" : "CEL"
}
}
}

Flattened Representation

The flattened representation returns all entities in a single array, which is particularly useful when you need to perform batch operations on the retrieved entities. Instead of nesting linked entities, it places them alongside the main entity.

GET Entity with Flat Links
GET /ngsi-ld/v1/entities/urn:ngsi-ld:Room:Room-101?join=flat&joinLevel=1
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

The response provides a flat structure where both the room and its linked building appear as separate entities in the array.

When working with knowledge graphs, you often need to handle large collections of entities. Whether you're querying all rooms in a building, all sensors in a city, or traversing complex relationship chains, pagination helps you process these results efficiently. Let's explore how to use pagination parameters to manage large result sets.

Pagination

Now that we understand how to query entities and traverse their relationships, let's explore how to handle large result sets efficiently through pagination When dealing with large sets of entities, it's important to use pagination to manage the amount of data returned in a single request. NGSI-LD provides two parameters for pagination: limit and offset.

  • limit: Specifies the maximum number of entities to return.
  • offset: Indicates the number of entities to skip before starting to return results.

Here's an example of how to use pagination:

GET Entities with Pagination
GET /ngsi-ld/v1/entities?type=Room&limit=10&offset=20
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query retrieves up to 10 Room entities, starting from the 21st entity in the result set. Since there are only two Room entities, using offset=20 will skip both of them, so the response will be empty.

tip

When using pagination, it's important to note:

  • The total count of matching entities is not provided by default.
  • The order of entities is not guaranteed unless you specify a sorting criterion.
  • For consistent paging through a large result set, consider using a combination of sorting and pagination.

To retrieve subsequent pages, increment the offset value by the limit:

// First page
GET /ngsi-ld/v1/entities?type=Room&limit=10&offset=0

// Second page
GET /ngsi-ld/v1/entities?type=Room&limit=10&offset=10

// Third page
GET /ngsi-ld/v1/entities?type=Room&limit=10&offset=20

By using pagination, you can efficiently process large datasets without overwhelming your application or the NGSI-LD server.

Geospatial Queries

NGSI-LD supports geospatial capabilities, allowing you to filter entities based on their location. This feature is useful for building location-aware solutions across various domains. Applications in mobility services, supply chain management, environmental monitoring, and urban infrastructure can benefit from efficient processing and analysis of location-based data.

Representing Geospatial Data

In NGSI-LD, geospatial properties are represented using the GeoProperty type and follow the GeoJSON format. For example, our building entity has a location attribute:

"location": {
"type": "GeoProperty",
"value": {
"type": "Point",
"coordinates": [-0.104049, 51.517417]
}
}

Basic Geospatial Query

Let's say we want to find all buildings within a 2000-meter radius of a specific point. We can use the following query:

GET Buildings Near Point
GET /ngsi-ld/v1/entities?type=Building&georel=near;maxDistance==2000&geometry=Point&coordinates=[-0.10,51.52]
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This query uses several geospatial parameters:

  • georel: Specifies the geospatial relationship, in this case, "near" with a maximum distance.
  • geometry: Defines the type of geometry we're using for the query (a Point).
  • coordinates: Provides the reference point coordinates [longitude, latitude].

If you've created the urn:ngsi-ld:Building:Office-1 entity, it should appear in the results as it's within this radius.

Advanced Geospatial Query

For more complex scenarios, you might want to find entities within a specific area. Let's query for all buildings and rooms within a polygon that represents a city district:

GET Entities in Polygon
GET /ngsi-ld/v1/entities?type=Building,Room&georel=within&geometry=Polygon&coordinates=[[[-0.12389517563002528,51.5175821932246],[-0.10448592463842488,51.50306475867603],[-0.08124704564784224,51.51823211940348],[-0.1052692576379286,51.528575529208354],[-0.12389517563002528,51.5175821932246]]]
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

In this query:

  • We're looking for both Buildings and Rooms (type=Building,Room).
  • The georel is set to "within", meaning we want entities inside the polygon.
  • The geometry is a Polygon, and coordinates defines its shape.

This query will return all buildings and rooms located within the specified polygon area.

tip
  • You can use tools like geojson.io to easily create and visualize GeoJSON polygons for your queries.
  • Remember to URL-encode special characters in your actual API calls.
  • NGSI-LD supports various GeoJSON geometries including Point, MultiPoint, LineString, MultiLineString, Polygon, and MultiPolygon.

These geospatial capabilities enable you to build sophisticated location-aware applications. While geospatial queries help you understand where entities are located in space, temporal queries help you understand how they change over time. Let's explore how NGSI-LD handles this temporal dimension of context information.

Working with Temporal Data

NGSI-LD provides built-in support for temporal context through its dedicated temporal interface (/ngsi-ld/v1/temporal/entities). This capability enables you to track how entities and their attributes evolve over time, essential for trend analysis, historical reporting, and predictive applications.

Storing Temporal Data

When creating or updating entities, including the observedAt temporal property automatically triggers historical data storage. For example, a temperature reading with its measurement timestamp looks like this:

{
"temperature": {
"type": "Property",
"value": 25.1,
"unitCode": "CEL",
"observedAt": "2024-02-22T12:30:00Z"
}
}

To create this temporal record, update the entity using the standard entity interface. Note that temporal properties must use UTC time in ISO 8601 format:

PATCH Entity Temporal
PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:Room:Room-101/attrs
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: {
"temperature": {
"type": "Property",
"value": 25.1,
"unitCode": "CEL",
"observedAt": "2025-02-23T11:30:00Z"
}
}

Querying Historical Data

Once temporal data is stored, you can access it through the temporal interface (/ngsi-ld/v1/temporal/entities). This interface provides several ways to retrieve and analyze historical data.

Retrieve Last N Values

To access the most recent historical values, use the lastN parameter. The response includes an array of temporal instances for the specified attributes:

{
"id" : "urn:ngsi-ld:Room:Room-101",
"type" : [ "MeetingRoom", "Room" ],
"temperature" : [ {
"type" : "Property",
"measuredBy" : {
"type" : "Relationship",
"object" : "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
},
"value" : 23.8,
"instanceId" : "instanceid:35163ac7-17cf-475f-b925-1aa8bdbf51d0",
"observedAt" : "2025-02-23T12:45:00Z",
"unitCode" : "CEL"
}, {
"type" : "Property",
"measuredBy" : {
"type" : "Relationship",
"object" : "urn:ngsi-ld:AirQualityIndoorSensor:AIQ-001"
},
"value" : 23.1,
"instanceId" : "instanceid:31fefb69-2adc-4924-a5e5-2672c92eacc4",
"observedAt" : "2025-02-23T12:30:00Z",
"unitCode" : "CEL"
}, {
"type" : "Property",
"value" : 21.7,
"instanceId" : "instanceid:ba627c6d-a029-4f96-801d-85981c1a2416",
"observedAt" : "2025-02-23T12:00:00Z",
"unitCode" : "CEL"
} ]
}

To retrieve these values, specify the attributes you want and the number of recent values:

GET Temporal Last N
GET /ngsi-ld/v1/temporal/entities/urn:ngsi-ld:Room:Room-101?attrs=temperature&lastN=3
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

Time Period Queries

For analyzing specific time periods, use the temporal parameters:

  • timerel: Temporal relationship ("between", "before", or "after")
  • timeAt: The reference timestamp
  • endTimeAt: The end timestamp (when using "between")

The response follows the same format as above but includes values within the specified time range:

GET Temporal Period
GET /ngsi-ld/v1/temporal/entities/urn:ngsi-ld:Room:Room-101?attrs=temperature&timerel=between&timeAt=2024-02-20T12:00:00Z&endTimeAt=2024-02-23T13:00:00Z
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

Temporal Aggregations

For statistical analysis, use the aggrMethods parameter. The response includes the calculated values and their temporal coverage:

{
"id" : "urn:ngsi-ld:Room:Room-101",
"type" : [ "MeetingRoom", "Room" ],
"temperature" : {
"type" : "Property",
"avg" : [
[ 23.425, "2025-02-23T11:30:00.000000Z", "2025-02-23T12:45:00.000000Z" ]
],
"max" : [
[ 25.1, "2025-02-23T11:30:00.000000Z", "2025-02-23T12:45:00.000000Z" ]
],
"min" : [
[ 21.7, "2025-02-23T11:30:00.000000Z", "2025-02-23T12:45:00.000000Z" ]
],
"totalCount" : [
[ 4, "2025-02-23T11:30:00.000000Z", "2025-02-23T12:45:00.000000Z" ]
]
}
}

Available aggregation methods include avg (average value), min, max, stddev (standard deviation), sum, totalCount (total number of values), distinctCount (count of unique values), sumsq (sum of squares). For example:

GET Temporal Aggregation
GET /ngsi-ld/v1/temporal/entities/urn:ngsi-ld:Room:Room-101?attrs=temperature&aggrMethods=avg,max,min,totalCount
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
tip

While NGSI-LD stores temporal data automatically when you include temporal properties, Garnet Framework also creates a data lake in Amazon S3 that captures all context information. This enables you to perform complex historical analysis using tools like Amazon Athena. See the "Building Data Consumers" section for more details.

Real-time Updates with Subscriptions

NGSI-LD subscriptions enable applications to receive real-time notifications when context changes match specific conditions. Rather than continuously polling for updates, applications can subscribe to relevant changes and receive immediate notifications. By combining geospatial capabilities and the NGSI-LD query language we explored earlier, subscriptions become a powerful tool for building sophisticated monitoring systems. This makes them particularly valuable for autonomous agents, smart city applications, or any system requiring contextual awareness and real-time responses.

For example, an autonomous fleet management system could receive notifications about vehicles exceeding speed limits in specific areas, while a building management system could monitor temperature patterns across different zones. This asynchronous mechanism is fundamental for building reactive, event-driven systems that can adapt to changing conditions in real-time.

Subscription Capabilities

NGSI-LD subscriptions offer flexible ways to specify which entities to monitor. You can subscribe to all entities of specific types, monitor individual entities by their unique identifiers, or use regular expressions with idPattern to match groups of entities with similar IDs. These capabilities can be combined to create highly targeted subscriptions that match your specific use cases.

Subscription Structure

A subscription defines what changes to monitor and where to send notifications. Let's look at a comprehensive example that combines multiple NGSI-LD capabilities:

{
"id": "urn:ngsi-ld:Subscription:VehicleMonitoring",
"type": "Subscription",
"description": "Monitor high-speed vehicles in specific area",
"entities": [
{
"type": "Vehicle"
}
],
"watchedAttributes": ["speed"],
"q": "speed>50",
"geoQ": {
"georel": "near;maxDistance==2000",
"geometry": "Point",
"coordinates": [-0.1094022, 51.5172398]
},
"notification": {
"attributes": ["speed", "location", "vehicleType"],
"format": "normalized",
"endpoint": {
"uri": "https://your-endpoint.example.com/notifications",
"accept": "application/json"
}
}
}

This subscription demonstrates several key features of the NGSI-LD subscription model:

  • Entity filtering: Monitor all vehicles using type-based filtering
  • Attribute monitoring: Watch changes in specific attributes (watchedAttributes)
  • Query conditions: Filter notifications based on attribute values (q)
  • Geospatial constraints: Limit notifications to entities within specific areas
  • Selective notification: Include only relevant attributes in the payload
  • Endpoint configuration: Specify where to send notifications

The NGSI-LD specification also supports subscribing to specific entity IDs or using regular expressions with idPattern to match groups of entities with similar IDs. This capability is particularly useful when you need to monitor specific instances rather than entire categories of entities.

The notification.endpoint.uri field can point to any HTTP endpoint capable of receiving POST requests with JSON payloads. This could be:

  • A webhook endpoint provided by your application
  • A serverless function (AWS Lambda, Azure Functions, etc.)
  • A message queue endpoint
  • A specialized notification service

For more detailed information about subscription capabilities from the ETSI GS CIM 009 specification, refer to the Deep Dive section.

Now, let's create a subscription for our smart building scenario to monitor room temperatures:

{
"id": "urn:ngsi-ld:Subscription:RoomTemperature",
"type": "Subscription",
"description": "Notify me when room temperature exceeds 25 degrees",
"entities": [
{
"type": "Room"
}
],
"watchedAttributes": ["temperature"],
"q": "temperature>25",
"notification": {
"format": "normalized",
"endpoint": {
"uri": "garnet:notification",
"accept": "application/json"
}
// Alternative: "uri": "${GARNET_PRIVATE_SUB_ENDPOINT}"
}
}

This subscription specifies:

  • A unique identifier (recommended format: urn:ngsi-ld:Subscription:{subscriptionName})
  • The entity types to monitor (entities)
  • Optional: Which attributes to watch (watchedAttributes)
  • Optional: A query condition (q)
  • Where to send notifications (endpoint)

Garnet Private Endpoint

Garnet Framework provides secure notification delivery mechanisms for subscriptions, giving you two options to choose from:

Standard Private REST API Endpoint

The original approach uses a private REST API endpoint (${GARNET_PRIVATE_SUB_ENDPOINT}) hosted on Amazon API Gateway, accessible only within the Garnet VPC. This endpoint receives notifications and then processes them to AWS IoT Core MQTT topics and the Garnet Data Lake.

Direct SQS Queue Delivery

As an additional option, the garnet:notification approach allows the NGSI-LD broker to send notifications directly to a dedicated SQS queue, bypassing the API Gateway. This provides a more streamlined delivery mechanism while maintaining the same downstream processing to IoT MQTT topics and Data Lake storage.

The garnet:notification approach offers several advantages:

  • Simpler configuration - no need to know the actual endpoint URL
  • Can be pre-programmed across environments
  • Particularly useful for autonomous agents creating their own subscriptions
  • Direct queue delivery for improved performance

Both options ultimately deliver notifications to the same MQTT topic pattern: garnet/subscriptions/{subscriptionName}, where {subscriptionName} is derived from the subscription's ID.

You can use the AWS IoT Core console's MQTT test client to subscribe to the garnet/# MQTT topic for testing your subscriptions in real-time. This provides an easy way to verify that your subscriptions are working correctly and to see the notification payloads.

Beyond testing, AWS IoT Rules can be configured to route these notifications to various downstream systems. For example, you could set up rules to trigger autonomous agents with the specific context information they need for actions, send alerts to monitoring systems, update dashboards, or integrate with other AWS services like Lambda, DynamoDB, or Amazon SQS.

For more detailed information about subscription capabilities, including advanced patterns and best practices, refer to the Deep Dive section.

Creating a Subscription

To create a subscription, use the /ngsi-ld/v1/subscriptions endpoint:

POST Subscription
POST /ngsi-ld/v1/subscriptions
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: {subscription}

Verifying Your Subscription

After creating a subscription, you can verify it was properly registered by listing all subscriptions:

GET Subscriptions
GET /ngsi-ld/v1/subscriptions
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'

This will return an array of all your active subscriptions, including the one you just created. The response includes detailed status information about each subscription:

[
{
"id": "urn:ngsi-ld:Subscription:RoomTemperature",
"type": "Subscription",
"description": "Updated description",
"jsonldContext": "context://urn:1bfaa089182dd87bcfec2b58888bd3f6",
"entities": [
{
"type": "Room"
}
],
"notification": {
"endpoint": {
"accept": "application/json",
"uri": "garnet:notification"
},
"lastNotification": "2025-08-26T15:41:54.983000Z",
"lastSuccess": "2025-08-26T15:41:54.983000Z",
"timesFailed": 0,
"timesSent": 2,
"status": "ok"
},
"q": "temperature>25",
"watchedAttributes": [
"temperature"
],
"status": "active"
}
]

The response provides valuable information about your subscription's health:

  • status: Overall subscription status (active, inactive, etc.)
  • notification.timesSent: Number of notifications successfully sent
  • notification.timesFailed: Number of failed notification attempts
  • notification.status: Current notification delivery status (ok, failed, etc.)
  • notification.lastSuccess: Timestamp of the last successful notification delivery
  • notification.lastFailure: Timestamp of the last failed notification attempt (if any)
  • notification.lastNotification: Timestamp of the most recent notification attempt
  • jsonldContext: The JSON-LD context being used for the subscription

You can also retrieve a specific subscription by its ID using GET /ngsi-ld/v1/subscriptions/{subscriptionId}.

Subscription Notifications

When a change matches the subscription criteria, a notification is sent. Here's an example notification:

{
"id": "urn:ngsi-ld:Notification:5e3da3c7-8632-4c93-8372-4c2f42bd3f22",
"type": "Notification",
"subscriptionId": "urn:ngsi-ld:Subscription:RoomTemperature",
"notifiedAt": "2025-02-23T15:01:00Z",
"data": [
{
"id": "urn:ngsi-ld:Room:Room-101",
"type": "Room",
"temperature": {
"type": "Property",
"value": 26.3,
"unitCode": "CEL",
"observedAt": "2025-02-23T15:00:00Z"
}
}
]
}

Monitoring Notifications

You can monitor notifications using several methods:

  1. Subscribe to MQTT topics using the AWS IoT Core MQTT test client: garnet/subscriptions/+
  2. Create AWS IoT Rules to process notifications and trigger actions
  3. Query historical notifications from the Garnet Data Lake
tip

When using either Garnet notification approach:

  • No additional security configuration is needed
  • Notifications are automatically preserved in the data lake
  • You can use AWS IoT Rules to build sophisticated event processing pipelines

Testing Your Subscription

Now that you understand how subscription notifications work and how to monitor them, let's test your subscription by updating a room's temperature to exceed our threshold of 25 degrees. This will trigger the notification system:

PATCH Entity to Trigger Notification
PATCH /ngsi-ld/v1/entities/urn:ngsi-ld:Room:Room-101/attrs
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: {
"temperature": {
"type": "Property",
"value": 27.5,
"unitCode": "CEL",
"observedAt": "2025-02-23T16:00:00Z"
}
}

This update sets the room temperature to 27.5°C, which exceeds our subscription threshold of 25°C. The subscription will detect this change and send a notification to the configured endpoint.

Managing Subscriptions

To update or delete a subscription, use the subscription's ID:

PATCH Subscription
PATCH /ngsi-ld/v1/subscriptions/{subscriptionId}
Headers:
'Authorization': ${GARNET_TOKEN}
'Content-Type': 'application/json'
Body: {
"description": "Updated description"
}

To delete a subscription:

DELETE Subscription
DELETE /ngsi-ld/v1/subscriptions/{subscriptionId}
Headers:
'Authorization': ${GARNET_TOKEN}

Conclusion

In this guide, we've explored how to use the NGSI-LD API to build and manage your knowledge graph. From discovering available types and attributes to creating entities with rich relationships, from querying with spatial awareness to tracking temporal evolution, and finally to implementing real-time monitoring through subscriptions, the NGSI-LD API provides comprehensive capabilities for context information management.

Next Steps

While the NGSI-LD API enables direct interaction with your knowledge graph, Garnet Framework offers additional capabilities to streamline data ingestion at scale. In the next section, we'll explore how to leverage Garnet's SQS-based ingestion mechanism, which provides automatic batching and reliable delivery for your Context Producers, particularly those built on AWS services. This approach simplifies the integration of various data sources while ensuring efficient and reliable updates to your knowledge graph.