REST to GraphQL Example: Exporting All N-central Devices

Let’s walk through a real-world example using one of N-central’s recipes - exporting all devices. First, we’ll look at how this works using REST, and then we’ll show how GraphQL simplifies and streamlines the process.

Notes

  • Ensure your network allows outbound HTTPS requests to api.n-able.com.
  • Replace "YOUR_TOKEN_HERE" with your actual API token.
  • Customise export paths or format as needed.

REST API Approach (PowerShell)

With REST, you need to:

    1. Call /customers to get customer info.
    1. Call /devices to get device info.
    1. Manually join the data in PowerShell.
    1. Format and export the result.
function NCentral-Customers {
    param ([string]$apiUrl, [string]$accessToken)
    $uri = "$apiUrl/api/customers"
    $headers = @{ "Authorization" = "Bearer $accessToken" }
    $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
    return $response.data
}
function NCentral-Devices {
    param ([string]$apiUrl, [string]$accessToken)
    $uri = "$apiUrl/api/devices"
    $headers = @{ "Authorization" = "Bearer $accessToken" }
    $response = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers
    return $response.data
}
$customers = NCentral-Customers -apiUrl $apiUrl -accessToken $accessToken
$devices = NCentral-Devices -apiUrl $apiUrl -accessToken $accessToken
$combinedTable = @()
foreach ($customer in $customers) {
    $customerDevices = $devices | Where-Object { $_.customerId -eq $customer.customerId }
    foreach ($device in $customerDevices) {
        $combinedTable += [PSCustomObject]@{
            "Customer ID"   = $customer.customerId
            "Customer Name" = $customer.customerName
            "Site Name"     = $device.siteName
            "Device ID"     = $device.deviceId
            "Device Name"   = $device.longName
            "Device Class"  = $device.deviceClass
        }
    }
}
$combinedTable | Format-Table -AutoSize

This method is effective, but it involves multiple API calls, manual data merging, and custom scripting - even though the query itself is relatively simple, accessing just two endpoints.

GraphQL Approach (Apollo Explorer)

With GraphQL, you can do all of this in one query to return a single response, already joined and structured

  • Device ID, name, class, and site.
  • Customer ID and name.
query GetAllNCentralDevices{
  assetSearch {
    nodes {
      id
      name
      customer {
        id
        name
      }
      operatingSystemInfo {
        name
        architecture
        type
      }
    }
  }
}

If you want to add or remove fields, simply alter the query and run it again. The response updates instantly with no need to change endpoints or reprocess data.

Bonus Features with GraphQL

Dynamic Field Selection

Choose only the fields you need - no overfetching.

Built-in Sorting

Want to sort the results based on a field? Just add orderBy the field: you want to use and direction:. For example, to sort by Customer Name and descending add:

query GetAllNCentralDevices{
  assetSearch(orderBy: { field: CUSTOMER_NAME, direction: DESC }) {
    ...
  }
}

Switch to ascending with direction: ASC.

Simplified Automation

Once your query is ready, you can plug it directly into a PowerShell script. Instead of juggling multiple REST calls, you make one GraphQL request that returns exactly what you need.

PowerShell with GraphQL

You can also use this query directly in PowerShell to programmatically retrieve the information.

Prerequisites

  • Ensure the PSGraphQL module is installed and available in your PowerShell session.

Example PowerShell script

# Ensure the PSGraphQL module is available in the session.
# Without this step, PowerShell won’t recognise the commands defined in the module.
# If omitted, your script will fail with “command not found” errors.
Import-Module PSGraphQL
# Set the GraphQL API endpoint and define a placeholder for the authentication token.
$endpoint = "https://api.n-able.com/graphql"
$token = "YOUR_TOKEN_HERE"
# Prepare the HTTP headers using the bearer token for authentication.
$headers = @{
    "Authorization" = "Bearer $token"
}
# Define a multi-line GraphQL query using a here-string: $query = @"..."@
# Enter the query to retrieve the device information including customer details, OS type, and chassis types.
$query = @"
query Query {
    assetSearch(orderBy: [{
        direction: DESC
        field: NAME
    }]) {
        nodes {
            customer {
                id
                name
            }
            operatingSystemInfo {
                type
                architecture
            }
            chassis {
                types 
            }
        }
    }
}
"@

Next Steps

Include the following command to send the GraphQL query to the N-able API and store the returned data in a $response.

$response = Invoke-RestMethod -Uri $endpoint -Method Post -Headers $headers -Body (@{ query = $query } | ConvertTo-Json -Depth 10)

What to do with the data….

Once the data is stored in $response, you can:

View the data in the console

$response.data.assetSearch.nodes | Format-Table

Export the data to CSV

$response.data.assetSearch.nodes | Export-Csv -Path "C:\Reports\DeviceReport.csv" -NoTypeInformation

Convert to JSON and save

$response | ConvertTo-Json -Depth 10 | Out-File "C:\Reports\DeviceData.json"

Generate HTML and save

$response.data.assetSearch.nodes | ForEach-Object {"$($_.customer.name) - $($_.operatingSystemInfo.type)"} | Out-File "C:\Reports\DeviceList.html"

How to use the $response in a Script

$response = Invoke-RestMethod -Uri $endpoint -Method Post -Headers $headers -Body (@{ query = $query } | ConvertTo-Json -Depth 10)
$response.data.assetSearch.nodes | Export-Csv -Path "C:\Reports\DeviceReport.csv" -NoTypeInformation

Send the Query

The first line sends your GraphQL query to the API endpoint using a POST request. It includes:

  • The endpoint URL ($endpoint)
  • Authentication headers ($headers)
  • The query itself ($query), converted to JSON

The response from the API is stored in the $response variable.

Export the Results

The second line accesses the specific part of the response that contains the data records - $response.data.assetSearch.nodes - and exports them to a CSV file.

How Do You Know What to Enter as the Object Path?

The object path (e.g. $response.data.assetSearch.nodes) is based on the structure of the GraphQL response, which in turn is defined by the structure of your query.

{
  "data": {
    "assetSearch": {
      "nodes": [
        {
          "customer": {
            "name": "Acme Corp"
          }
        }
      ]
    }
  }
}
  • $response is the full JSON response.
  • $response.data accesses the "data" section.
  • $response.data.assetSearch accesses the "assetSearch" object.
  • $response.data.assetSearch.nodes accesses the array of results under "nodes".

PowerShell example including $response and Export-CSV

Import-Module PSGraphQL
$endpoint = "https://api.n-able.com/graphql"
$token = "YOUR_TOKEN_HERE"
$headers = @{
    "Authorization" = "Bearer $token"
}
$query = @"
query Query {
    assetSearch(orderBy: [{
        direction: DESC
        field: NAME
    }]) {
        nodes {
            customer {
                id
                name
            }
            operatingSystemInfo {
                type
                architecture
            }
            chassis {
                types 
            }
        }
    }
}
"@
# Send the GraphQL query using Invoke-RestMethod.
# The response is stored in the $response variable.
$response = Invoke-RestMethod -Uri $endpoint -Method Post -Headers $headers -Body (@{ query = $query } | ConvertTo-Json -Depth 10)
# Export the results to a CSV file for reporting.
$response.data.assetSearch.nodes | Export-Csv -Path "C:\Reports\DeviceReport.csv" -NoTypeInformation