Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Table of Contents

GraphQL Occupancy API offers similar functionality to REST Occupancy API, however, there are additional benefits to using GraphQL.

You can select the fields you want to receive from the API. By requesting only the required fields from the API you can decrease traffic and consequently increase load speed.

Additionally, GraphQL Occupancy API supports subscriptions, which allows you to receive real-time occupancy updates.

Authorization

In order to authorize with this API, you need to add the following header to your request:

Key

Value

Authorization

<your token>

Your token can be obtained from the Company Info section of the Nwave’s console.

Object & Field Descriptions

PositionOccupancy - describes a position and its occupancy state

  • id - position id

  • customId - user-defined id

  • groupId - position’s group id

  • occupancyStatus - parking space occupancy status

  • statusChangeTime - latest occupancy status change time

  • location - object containing latitude and longitude coordinates
  • GroupOccupancy - describes a group, its positions and their occupancy states

    • id - group id

    • name - group user-defined name

    • customId - group user-defined id

    • location - object containing latitude and longitude coordinates

    • positionsOccupancy - list of all positions inside a group with its occupancy information

    • summary - group occupancy summary (total positions number, number of occupied and free positions)

  • Info

    The summary object should be used to display availability for all parking group types

    • SubscriptionArea - special object for describing occupancy states changes for some area

      • id - area id

      • location - object containing latitude and longitude coordinates

      • radius - area’s radius in meters

      • granularity - user-defined type for returned objects. Available values: [Position, Level, Group, Zone]

      • updates - list of Occupancy objects. Type of objects depends on the selected granularity option.

      • updateTime - the time of last occupancy status update

    Documentation

    The following GraphQL schema describes data types and operations that can be performed.

    Code Block
    languagegraphql
    schema

    GraphQL Schema

    The following GraphQL schema describes data types and operations that can be performed.

    File:

    View file
    nameschema.graphql

    Expand
    titleschema.graphql
    Code Block
    languagegraphql
    schema {
        query: Query
        mutation: Mutation
        subscription: Subscription
    }
    
    enum OccupancyStatus {
        Occupied
        Free
    }
    
    enum SubscriptionGranularity {
        Position
        Level
        Group
        Zone
    }
    
    type Location @aws_api_key @aws_lambda {
        lat: Float!
        lon: Float!
    }
    
    input LocationInput {
        
    query
    lat: 
    Query
    Float!
        
    mutation
    lon: 
    Mutation
    Float!
    }
    
    type OccupancySummary 
    subscription: Subscription } enum OccupancyStatus { Occupied Free } enum SubscriptionGranularity {
     @aws_api_key @aws_lambda {
        total: Int!
        occupied: Int!
        available: Int!
        
    Position Level Group Zone
    undefined: Int!
    }
    
    
    type Location @aws_api_key @aws_lambda
    input OccupancySummaryInput {
        
    lat
    total: 
    Float
    Int!
        
    lon
    occupied: 
    Float! } input LocationInput {
    Int!
        
    lat
    available: 
    Float
    Int!
        
    lon
    undefined: 
    Float
    Int!
    }
    
    type 
    OccupancySummary
    PositionOccupancy  @aws_api_key @aws_lambda {
        
    total
    id: Int!
        
    occupied
    customId: 
    Int!
    String
        
    available
    groupId: Int
    !
    
        
    undefined
    occupancyStatus: 
    Int!
    OccupancyStatus
    
    }
      
    input
     
    OccupancySummaryInput { total
     statusChangeTime: 
    Int!
    AWSDateTime
        
    occupied
    location: 
    Int! available: Int! undefined: Int
    Location!
    }
    
    
    type PositionOccupancy @aws_api_key @aws_lambda
    input PositionOccupancyInput {
        id: Int!
        customId: String
        groupId: Int!
        occupancyStatus: OccupancyStatus!
        statusChangeTime: AWSDateTime!
        location: 
    Location
    LocationInput!
    }
    
    type 
    input PositionOccupancyInput
    GroupOccupancy  @aws_api_key @aws_lambda {
        id: Int!
        
    customId
    zoneId: 
    String
    Int
        
    groupId
    levelId: Int
    !
    
        
    occupancyStatus
    name: 
    OccupancyStatus
    String!
        
    statusChangeTime
    groupType: 
    AWSDateTime
    String!
        
    location: LocationInput! } type GroupOccupancy @aws_api_key @aws_lambda { id: Int! zoneId: Int levelId: Int name: String! groupType: String! customId:
    customId: String
        location: Location
        positionsOccupancy: [PositionOccupancy]
        summary: OccupancySummary
    }
    
    input GroupOccupancyInput {
        id: Int!
        zoneId: Int
        levelId: Int
        name: String!
        groupType: String!
        customId: String
        location: LocationInput!
        positionsOccupancy: [PositionOccupancyInput!]!
        summary: OccupancySummaryInput!
    }
    
    type LevelOccupancy  @aws_api_key @aws_lambda {
        id: Int
        name: String
        zoneId: Int!
        floorNumber: Int
        summary: OccupancySummary
    }
    
    input LevelOccupancyInput {
        id: Int
        zoneId: Int!
        floorNumber: Int
        name: String
        summary: OccupancySummaryInput!
    }
    
    type ZoneOccupancy  @aws_api_key @aws_lambda {
        id: Int!
        name: String!
        projectId: 
    String
    Int
        summary: OccupancySummary
    }
    
    input ZoneOccupancyInput {
        id: Int!
        name: String!
        projectId: Int
        summary: OccupancySummaryInput!
    }
    
    union RtaUpdateObject = ZoneOccupancy | LevelOccupancy | GroupOccupancy | PositionOccupancy
    
    interface SubscriptionArea {
        id: Int!
        location: Location
        radius: Int
        zoneId: [Int]
        levelId: [Int]
        floorNumber: [Int]
        groupId: [Int]
        labels: [String]
        granularity: SubscriptionGranularity!
        expiresOn: AWSDateTime!
    }
    
    type SubscriptionAreaNoUpdates implements SubscriptionArea @aws_api_key @aws_lambda {
        id: Int!
        location: Location
        radius: Int
        zoneId: [Int]
        levelId: [Int]
        floorNumber: [Int]
        groupId: [Int]
        labels: [String]
        granularity: SubscriptionGranularity!
        expiresOn: AWSDateTime!
    }
    
    type SubscriptionAreaWithUpdates implements SubscriptionArea @aws_api_key @aws_lambda {
        id: Int!
        location: Location
        radius: Int
        zoneId: [Int]
        levelId: [Int]
        floorNumber: [Int]
        groupId: [Int]
        labels: [String]
        granularity: SubscriptionGranularity!
        expiresOn: AWSDateTime!
        updates: [RtaUpdateObject]
        updateTime: AWSDateTime
    }
    
    type Query {
        groupOccupancy(id: Int!): GroupOccupancy @aws_api_key @aws_lambda
        findGroupOccupancies(
            ids: [Int]
            lat: Float
            lon: Float
            radius: Int
            levelId: [Int!]
            floorNumber: [Int!]
            zoneId: [Int!]
            projectId: Int
            groupCustomId: String
            limit: Int = 50
            offset: Int
        ) : [GroupOccupancy] @aws_api_key @aws_lambda
        findPositionOccupancies(
            ids: [Int]
            lat: Float
            lon: Float
            radius: Int
            groupId: [Int!]
            levelId: [Int!]
            floorNumber: [Int!]
            zoneId: [Int!]
            projectId: Int
            groupCustomId: String
            limit: Int = 50
            offset: Int
        ) : [PositionOccupancy] @aws_api_key @aws_lambda
    }
    
    type Mutation {
        createSubscriptionArea(
            lat: Float,
            lon: Float,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity
        ): SubscriptionAreaNoUpdates @aws_api_key @aws_lambda
        updateSubscriptionArea(
            id: Int!,
            lat: Float,
            lon: Float,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity
        ): SubscriptionAreaNoUpdates @aws_api_key @aws_lambda
        updatePositionOccupancy(
            positionId: Int!,
            occupancyStatus: OccupancyStatus!,
            timestamp: String!
        ): PositionOccupancy @aws_api_key
        pushPositionUpdates(
            id: Int!,
            location: LocationInput,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity!,
            expiresOn: AWSDateTime!,
            updates: [PositionOccupancyInput!]!,
            updateTime: String!
        ): SubscriptionAreaWithUpdates @aws_api_key
        pushGroupUpdates(
            id: Int!,
            location: LocationInput,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity!,
            expiresOn: AWSDateTime!,
            updates: [GroupOccupancyInput!]!,
            updateTime: String!
        ): SubscriptionAreaWithUpdates @aws_api_key
        pushLevelUpdates(
            id: Int!,
            location: LocationInput,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity!,
            expiresOn: AWSDateTime!,
            updates: [LevelOccupancyInput!]!,
            updateTime: String!
        ): SubscriptionAreaWithUpdates @aws_api_key
        pushZoneUpdates(
            id: Int!,
            location: LocationInput,
            radius: Int,
            zoneId: [Int],
            levelId: [Int],
            floorNumber: [Int],
            groupId: [Int],
            labels: [String],
            granularity: SubscriptionGranularity!,
            expiresOn: AWSDateTime!,
            updates: [ZoneOccupancyInput!]!,
            updateTime: String!
        ): SubscriptionAreaWithUpdates @aws_api_key
    } type Subscription { onSubscriptionAreaUpdates(id: Int!): SubscriptionAreaWithUpdates @aws_api_key @aws_lambda @aws_subscribe(mutations : ["pushPositionUpdates", "pushGroupUpdates", "pushLevelUpdates", "pushZoneUpdates"]) }
    
    }
    
    type Subscription {
        onSubscriptionAreaUpdates(id: Int!): SubscriptionAreaWithUpdates @aws_api_key @aws_lambda @aws_subscribe(mutations : ["pushPositionUpdates", "pushGroupUpdates", "pushLevelUpdates", "pushZoneUpdates"])
    }

    Subscription Areas

    A subscription area is an object that has two main functions:

    1. Filtering of the incoming position updates

    2. Defining the format of updates that is received by subscribers

    There are two types defined in the GraphQL schema for Subscription Areas:

    SubscriptionAreaNoUpdates - this type is returned when you create or update a Subscription Area. It does not have ‘updates’ & ‘updateTime’ fields as updates are only returned to active subscriptions.

    Info

    Subscription areas 5 minutes after creation. Any update of a subscription area, including an empty one, will extend the expiration time by 5 minutes from the time of update.

    SubscriptionAreaWithUpdates - this type is returned to subscribers and as the name suggests it contains the ‘updates’ & ‘updateTime’ fields.

    Subscription Area Filters

    Subscription Areas filter the incoming updates and only notify the subscribers if the incoming position update matches all of the filters. Subscription Area filters can also be split into 2 categories:

    1. Hierarchical Filters: zoneId, groupId, levelId, floorNumber, labels

    2. Geospatial Filters: lat, lon, radius

    Info

    A valid subscription area must have at least one hierarchical filter and/or all of the geospatial filters.

    A match is when all position attributes are a subset (⊆) of the Subscription Area filters.

    Subscription Area filter with null value matches everything.

    The following example is a valid match between Subscription Area and Position Update.

    Position

    1. zoneId: 1

    2. groupId: 2

    3. levelId: 3

    4. floorNumber: 4

    5. labels: ['EV', ‘Disabled’]

    6. lat: 0.0

    7. lon: 0.0

    Subscription Area

    1. zoneId: [1, 2, 3]

    2. groupId: [1, 2, 3]

    3. levelId: [3]

    4. floorNumber: null

    5. lables: ['EV', ‘Disabled’, ‘VIP’]

    6. lat: 0.0

    7. lon: 0.0

    8. radius: 100

    Note

    Geospatial filters create a circular search area on the map, and there can be cases when a group of devices partially falls into the search area. (e.g. Half a group is within the search area and half is outside of the search area).

    Updates for positions that do not fall into the search area would still notify the subscribers.

    Subscription Area Updates

    The updates field of a Subscription Area can contain a list of 4 different types. All types within the updates list are the same. The type you will receive in the updates field depends on the granularity you choose.

    Granularity

    Updates Type

    Zone

    ZoneOccupancy

    Level

    LevelOccupancy

    Group

    GroupOccupancy

    Position

    PositionOccupancy

    Info

    Updates field will always contain only the object that has changed and therfore the list should always have a length of 1.

    Object & Field Descriptions

    SubscirptionArea

    • id - subscription area id

    • location - center coordinates of the search area

    • radius - radius from the center in meeters that creates the search area

    • zoneId - list of zone ids to match

    • levelId - list of level ids to match

    • floorNumber - list of floor numbers to match

    • groupId - list of group ids to match

    • labels - list of labels to match

    • granularity - defines the updates type

    • expiresOn - timestamp of subscription area expiration

    • udpates - occupancy updates for a subscription area

    • updateTime - timestamp of the occupancy update

    ZoneOccupancy

    • id - zone id

    • name - zone name

    • projectId - project id

    • summary - summary of occupancies in the Zone

    LevelOccupancy

    • id - level id

    • name - level name

    • zoneId - zone id

    • floorNumber - floor number of a level

    • summary - summary of occupancies on a Level

    GroupOccupancy

    • id - group id

    • zoneId - zone id

    • levelId - level id

    • name - group name

    • groupType - group type e.g. marked_bay

    • customId - user defined group id

    • location - сenter coordinates of a group

    • positionOccupancy - list of PositionOccupancy objects for a group

    • summary - summary of occupancies in the Group

    PositionOccupancy

    • id - position id

    • customId - custom id

    • groupId - group id

    • occupancyStatus - ‘occupied’, ‘free’ or null

    • statusChangeTime - timestamp of last occupancyStatus change

    • location: coordinates of a position

    Info

    The summary object should be used to display availability for all parking group types as it handles unmarked bay occupancies

    Operations

    The following operations can be performed using either Postman or curl command except for subscription operations.

    groupOccupancy

    This query will return the occupancy of a single group.

    Query

    Code Block
    languagegraphql
    query MyQuery {
      groupOccupancy(id: 123) {
        id
        customId
        name
        location {
          lat
          lon
        }
        positionsOccupancy {
          customId
          id
          groupId
          location {
            lat
            lon
          }
          occupancyStatus
          statusChangeTime
        }
      }
    }

    Response

    Code Block
    languagejson
    {
      "data": {
        "groupOccupancy": {
          "id": 3544,
          "customId": null,
          "name": "Foo",
          "location": {
            "lat": 51.493601937687224,
            "lon": -0.12852029611716095
          },
          "positionsOccupancy": [
            {
              "customId": "",
              "id": 1,
              "groupId": 123,
              "location": {
                "lat": 51.49360068522545,
                "lon": -0.1286061268139623
              },
              "occupancyStatus": "Free",
              "statusChangeTime": "2021-01-27T19:22:47.548+00:00"
            },
            {
              "customId": "",
              "id": 2,
              "groupId": 123,
              "location": {
                "lat": 51.493601937687224,
                "lon": -0.12852029611716098
              },
              "occupancyStatus": "Occupoed",
              "statusChangeTime": "2021-01-27T18:56:53.502+00:00"
            }
          ]
        }
      }
    }

    findGroupOccupancies

    This query will return a list of group occupancies.

    Query

    Code Block
    languagegraphql
    query MyQuery {
      findGroupOccupancies(ids: [1234]) {
        id
        location {
          lat
          lon
        }
        summary {
          available
          occupied
          total
          undefined
        }
      }
    }

     

    Response

    Code Block
    languagejson
    {
      "data": {
        "findGroupOccupancies": [
          {
            "id": 1234,
            "location": {
              "lat": 50.780416909504915,
              "lon": -1.0914407438684124
            },
            "summary": {
              "available": 34,
              "occupied": 13,
              "total": 47,
              "undefined": 0
            }
          }
        ]
      }
    }

    findPositionOccupancies

    This query will return a list of position occupancies.

    Query

    Code Block
    languagegraphql
    query MyQuery {
      findPositionOccupancies(ids: [1]) {
        id
        location {
          lat
          lon
        }
        occupancyStatus
        statusChangeTime
        groupId
        customId
      }
    }

     

    Response

    Code Block
    languagejson
    {
      "data": {
        "findPositionOccupancies": [
          {
            "id": 12345,
            "location": {
              "lat": 51.49360068522545,
              "lon": -0.1286061268139623
            },
            "occupancyStatus": "Free",
            "statusChangeTime": "2021-01-27T19:22:47.548+00:00",
            "groupId": 123,
            "customId": ""
          }
        ]
      }
    }

    createSubscriptionArea

    This mutation will create a new subscription area.

    Subscription Area Expiration

    By default, subscription areas expire 5 minutes after creation. Once a subscription area is expired, it cannot be extended and subscribers will stop receiving updates.

    Mutation

    Code Block
    languagegraphql
    mutation MyMutation {
      createSubscriptionArea(
        granularity: Group, 
        lat: 51.493930, 
        lon: -0.129030, 
        radius: 100
      ) {
        expiresOn
        granularity
        id
        location {
          lat
          lon
        }
        radius
      }
    }
    

     

    Response

    Code Block
    languagejson
    {
      "data": {
        "createSubscriptionArea": {
          "expiresOn": "2021-01-28T23:20:06.232+00:00",
          "granularity": "Group",
          "id": 1,
          "location": {
            "lat": 51.49393,
            "lon": -0.12903
          },
          "radius": 100
        }
      }
    }

    onSubscriptionAreaUpdates

    This subscription will subscribe to occupancy updates inside an area.

    Selected updates object type must correspond to the granularity of the created search area:

    1. granularity: Position → updates { … on PositionOccupancy }

    2. granularity: Group → updates { … on GroupOccupancy }

    If you are unsure of the granularity for your subscription area, you can specify both types inside the updates.

    Subscription

    Code Block
    languagegraphql
    subscription MySubscription {
      onSubscriptionAreaUpdates(id: 1) {
        id
        expiresOn
        granularity
        location {
          lat
          lon
        }
        radius
        updateTime
        updates {
          ... on GroupOccupancy {
            id
            name
            customId
            location {
              lat
              lon
            }
            positionsOccupancy {
              customId
              groupId
              id
              location {
                lat
                lon
              }
              occupancyStatus
              statusChangeTime
            }
            summary {
              undefined
              total
              occupied
              available
            }
          }
        }
      }
    }
    

     

    Update

    Code Block
    languagejson
    {
      "data": {
        "onSubscriptionAreaUpdates": {
          "id": 1,
          "expiresOn": "2021-01-28T23:20:06.232+00:00",
          "granularity": "Group",
          "location": {
            "lat": 51.49393,
            "lon": -0.12903
          },
          "radius": 1000,
          "updateTime": "2021-01-28T23:17:38.400+00:00",
          "updates": [
            {
              "id": 123,
              "name": "Foo",
              "customId": null,
              "location": {
                "lat": 51.493601937687224,
                "lon": -0.12852029611716095
              },
              "positionsOccupancy": [
                {
                  "customId": "",
                  "groupId": 123,
                  "id": 1,
                  "location": {
                    "lat": 51.49360068522545,
                    "lon": -0.1286061268139623
                  },
                  "occupancyStatus": "Occupied",
                  "statusChangeTime": "2021-01-28T23:17:38.400+00:00"
                }
              ],
              "summary": {
                "undefined": 0,
                "total": 1,
                "occupied": 1,
                "available": 0
              }
            }
          ]
        }
      }
    }
    

    updateSubscriptionArea

    This mutation will update an existing subscription area.

    Info

    All subscription area updates will extend expiration by 5 minutes from the current time.

    You can also send empty mutation to only update the expiration.

    Mutation

    Code Block
    languagegraphql
    mutation MyMutation {
      updateSubscriptionArea(
        id: 1, 
        granularity: Position, 
        radius: 500
      ) {
        expiresOn
        id
        granularity
        location {
          lat
          lon
        }
        radius
      }
    }
    

     

    Code Block
    languagegraphql
    mutation ExtendSubscription {
      updateSubscriptionArea(
        id: 1, 
      ) {
        expiresOn
        id
      }
    }
    

    Response

    Code Block
    languagejson
    {
      "data": {
        "updateSubscriptionArea": {
          "expiresOn": "2021-01-28T23:20:06.232134+00:00",
          "id": 1,
          "granularity": "Position",
          "location": {
            "lat": 51.49393,
            "lon": -0.12903
          },
          "radius": 500
        }
      }
    }

    Code Block
    languagejson
    {
      "data": {
        "updateSubscriptionArea": {
          "expiresOn": "2021-01-28T23:25:06.232134+00:00",
          "id": 1,
        }
      }
    }

    Use cases

    Query

    Use case

    Code Block
    languagegraphql
    query MyQuery {
      findGroupOccupancies(
        lat: 0.0, 
        lon: 0.0, 
        radius: 2000
      ) {
        location {
          lat
          lon
        }
        summary {
          available
        }
      }
    }
    Info

    The summary object should be used to display availability for all parking group types

    Displaying all parking groups within 2km in a mobile app

    Code Block
    languagegraphql
    query MyQuery {
      groupOccupancy(id: 1) {
        positionsOccupancy {
          location {
            lat
            lon
          }
          occupancyStatus
        }
      }
    }

    Displaying individual parking positions when a user approaches his desired parking location

    Code Block
    languagegraphql
    mutation MyMutation {
      createSubscriptionArea(
        granularity: Position, 
        lat: 1.5, 
        lon: 1.5, 
        radius: 2000
      ) {
        id
      }
    }
    subscription MySubscription {
      onSubscriptionAreaUpdates(
      id: <id from previous mutation>
      )
    }

    Displaying live parking statuses within 2km radius

    Code Block
    languagegraphql
    mutation MyMutation {
      updateSubscriptionArea(
        id: 1, 
      ) {
        expiresOn
        id
      }
    }

    Extend subscription area expiration

    Postman Collection

    Download Postman Collection here:

    View file
    nameGraphQL Occupancy.postman_collection.json

    Importing Collection

    1. Click import in My Workspace section.

    1. Upload the collection file and click

    Import.

    Adding API key to Postman Environment

    This collection uses the api_key variable to add an authorization token to the x-api-key header.

    1. To create a new environment click on the eye icon near the top right corner.

    2. Click Add to add a new environment.

    3. Add the gql_api_key variable name and your token in the initial value.

    4. Select the New Environment from the list.

    5. You can now test the requests in the GraphQL Occupancy Collection.