Data APIs
The Propel Data APIs let you expose any Data Pool (ClickHouse table) as an API. This guide covers the different APIs with examples of various data visualizations.
You can test your GraphQL API requests without writing a single line of code in our API Playground.
SQL API​
In Propel, you can use SQL to query your data. This way, you can easily take advantage of Propel's fast response times, high availability, and access controls with the convenience of familiar SQL syntax.
- Query
- Response
query {
sqlV1(input: {
query: """
SELECT *
FROM "TacoSoft Demo Data"
LIMIT 3
"""
}) {
columns {
columnName
}
rows
}
}
{
"sqlV1": {
"columns": [
{
"columnName": "quantity"
},
{
"columnName": "taco_name"
},
{
"columnName": "sauce_name"
},
{
"columnName": "restaurant_id"
},
{
"columnName": "restaurant_name"
},
{
"columnName": "taco_total_price"
},
{
"columnName": "order_item_id"
},
{
"columnName": "tortilla_id"
},
{
"columnName": "toppings"
},
{
"columnName": "sauce_id"
},
{
"columnName": "taco_unit_price"
},
{
"columnName": "order_id"
},
{
"columnName": "order_item_generated_at"
},
{
"columnName": "taco_id"
},
{
"columnName": "timestamp"
},
{
"columnName": "tortilla_name"
}
],
"rows": [
[
"1",
"Chorizo",
"Queso Blanco",
"f38ed454-a907-43b4-b362-cd4dd197dd03",
"La Taqueria",
"3.5",
"13dce1a3-c53f-4789-9804-cb4c1e191922",
"3898644e-f4f6-439f-ac9b-6c4c5a7704bb",
"[\"Lime\",\"Black beans\"]",
"54ba79c8-786e-46d4-a583-8b51df6a06e2",
"3.5",
"ddb63195-3053-44d1-8a7e-fc7b29de4685",
"2023-08-04T18:41:09.155Z",
"a7e7f311-018a-4393-9a65-90adfe851cc5",
"2023-08-04T17:41:09.155Z",
"Whole Wheat"
],
[
"2",
"Breakfast",
"Salsa Verde",
"f38ed454-a907-43b4-b362-cd4dd197dd03",
"La Taqueria",
"6",
"0ccdb522-69eb-4f26-9161-21edcfbacf5b",
"3898644e-f4f6-439f-ac9b-6c4c5a7704bb",
"[\"Lime\",\"Guacamole\",\"Black beans\",\"Mango\"]",
"56b4b6f6-0c1d-4949-927a-8a0057943c6b",
"3",
"ddb63195-3053-44d1-8a7e-fc7b29de4685",
"2023-08-04T18:41:09.155Z",
"492c0afd-7522-4fcb-a14a-4aab9f11da8d",
"2023-08-04T17:41:09.155Z",
"Whole Wheat"
],
[
"3",
"Veggie",
"Chipotle Mayo",
"f38ed454-a907-43b4-b362-cd4dd197dd03",
"La Taqueria",
"8.25",
"3951d8d5-b6d4-4c96-b829-1f73c30b7d59",
"3294dd90-073b-4b31-85a5-21bea72f1cac",
"[\"Lime\",\"Guacamole\"]",
"25cdef0f-c358-4788-9645-f9625b9a219f",
"2.75",
"ddb63195-3053-44d1-8a7e-fc7b29de4685",
"2023-08-04T18:41:09.155Z",
"6e27b959-b7dc-4b70-89bc-0f4562028604",
"2023-08-04T17:41:09.155Z",
"Corn"
]
]
}
}
Time Series​
The Time Series API returns values and labels for every time granule over the requested relative or absolute time range.
- Query
- Response
# Revenue over time
query {
timeSeries(input: {
metric: {
sum: {
dataPool: {
name: "TacoSoft Demo Data"
},
measure: {
columnName: "taco_total_price"
}
}
},
granularity: DAY,
timeRange: {
relative: LAST_N_DAYS,
n: 30
},
filterSql: "restaurant_name = 'El Buen Sabor'"
}) {
labels
values
}
}
{
"data": {
"timeSeries": {
"labels": [
"2023-08-03T00:00:00.000Z",
"2023-08-04T00:00:00.000Z",
"2023-08-05T00:00:00.000Z",
"2023-08-06T00:00:00.000Z",
"2023-08-07T00:00:00.000Z",
"2023-08-08T00:00:00.000Z",
"2023-08-09T00:00:00.000Z",
"2023-08-10T00:00:00.000Z",
"2023-08-11T00:00:00.000Z",
"2023-08-12T00:00:00.000Z",
"2023-08-13T00:00:00.000Z",
"2023-08-14T00:00:00.000Z",
"2023-08-15T00:00:00.000Z",
"2023-08-16T00:00:00.000Z",
"2023-08-17T00:00:00.000Z",
"2023-08-18T00:00:00.000Z",
"2023-08-19T00:00:00.000Z",
"2023-08-20T00:00:00.000Z",
"2023-08-21T00:00:00.000Z",
"2023-08-22T00:00:00.000Z",
"2023-08-23T00:00:00.000Z",
"2023-08-24T00:00:00.000Z",
"2023-08-25T00:00:00.000Z",
"2023-08-26T00:00:00.000Z",
"2023-08-27T00:00:00.000Z",
"2023-08-28T00:00:00.000Z",
"2023-08-29T00:00:00.000Z",
"2023-08-30T00:00:00.000Z",
"2023-08-31T00:00:00.000Z",
"2023-09-01T00:00:00.000Z"
],
"values": [
"0",
"182.25",
"744.25",
"494",
"830.5",
"582.75",
"637",
"347",
"694.75",
"529.5",
"512.75",
"922.25",
"623.5",
"1484.25",
"807.25",
"405.5",
"461.75",
"910.75",
"772",
"681",
"401.75",
"801.25",
"549.5",
"495.25",
"337.5",
"1248.5",
"377",
"544.5",
"553",
"0"
]
}
}
}
Counter​
The Counter API returns a single value for the requested relative or absolute time range.
- Query
- Response
# Last 30 days comparison
query {
revenueLast30Days: counter(input: {
metric: {
sum: {
dataPool: {
name: "TacoSoft Demo Data"
},
measure: {
columnName: "taco_total_price"
}
}
},
timeRange: {
relative: THIS_MONTH
},
filterSql: "restaurant_name = 'La Taqueria'"
}) {
value
}
revenuePrevious30Days: counter(input: {
metric: {
sum: {
dataPool: {
name: "TacoSoft Demo Data"
},
measure: {
columnName: "taco_total_price"
}
}
},
timeRange: {
relative: PREVIOUS_MONTH
},
filterSql: "restaurant_name = 'La Taqueria'"
}) {
value
}
}
{
"data": {
"revenueLast30Days": {
"value": "2940.34"
},
"revenuePrevious30Days": {
"value": "18366.75"
}
}
}
Data Grid​
The Data Grid API returns individual records from a Data Pool with the convenience of built-in pagination, filtering, and sorting.
- Query
- Response
query {
dataGrid(input: {
dataPool: {
name: "TacoSoft Demo Data"
},
timeRange: {
relative: THIS_YEAR
},
columns: [
"timestamp",
"order_item_id",
"taco_name",
"taco_total_price"],
orderByColumn: 1,
sort: DESC,
filterSql: "restaurant_name = 'La Taqueria'",
first: 5
}) {
headers
rows
pageInfo {
hasNextPage
hasPreviousPage
endCursor
startCursor
}
}
}
{
"dataGrid": {
"headers": [
"timestamp",
"order_item_id",
"taco_name",
"taco_total_price"
],
"rows": [
[
"2024-07-31T21:50:53.866Z",
"7e93840a-6087-4bb6-9622-97802b276c67",
"Chorizo",
"14"
],
[
"2024-07-31T21:50:53.866Z",
"bd6f32b4-c68c-485f-9b32-d8f186bfac6b",
"Chorizo",
"10.5"
],
[
"2024-07-31T21:50:53.866Z",
"4df6116a-69e4-49ae-b1c0-8dd47409c6cc",
"Chorizo",
"14"
],
[
"2024-07-31T21:50:53.866Z",
"0b299045-291e-4f24-8f51-361e4e77c18a",
"Breakfast",
"12"
],
[
"2024-07-31T21:40:53.866Z",
"0e26e52d-0e08-42c0-8a0e-e0e3f1d19dc4",
"Chorizo",
"3.5"
]
],
"pageInfo": {
"hasNextPage": true,
"hasPreviousPage": false,
"endCursor": "eyJvZmZzZXQiOjR9",
"startCursor": "eyJvZmZzZXQiOjB9"
}
}
}
Leaderboard​
The Leaderboard API returns an ordered list of aggregated values grouped by a given dimension.
- Query
- Response
# Top 10 restaurants by revenue
query {
leaderboard(input: {
metric: {
sum: {
dataPool: {
name: "TacoSoft Demo Data"
},
measure: {
columnName: "taco_total_price"
}
}
},
sort: DESC,
timeRange: {
relative: LAST_N_DAYS,
n: 30
},
rowLimit: 10,
dimensions: [
{
columnName: "restaurant_name"
}
],
filterSql: ""
}) {
headers
rows
}
}
{
"data": {
"leaderboard": {
"headers": ["restaurant_name", "value"],
"rows": [
["Farolito", "4064"],
["Los Compadres", "4025.5"],
["Taqueria Cancun", "3835"],
["Taqueria Vallarta", "3736.25"],
["La Taqueria", "3646.75"],
["El Buen Sabor", "3443.5"]
]
}
}
}
Metric Report​
The Metric Report API returns one or multiple metrics grouped by a common dimension.
- Query
- Response
# Fetch a report showing the revenue and taco order
# count for the top performing restaurant-taco pairs.
query {
metricReport(input: {
timeRange: {
relative: LAST_N_DAYS,
n: 30
},
dimensions: [
{
columnName: "restaurant_name"
},
{
columnName: "taco_name"
}
],
metrics: [
{
metric: {
sum: {
dataPool: {
name: "TacoSoft Demo Data"
},
measure: {
columnName: "taco_total_price"
}
}
}
},
{
metric: {
countDistinct: {
dataPool: {
name: "TacoSoft Demo Data"
},
dimension: {
columnName: "order_id"
}
}
}
}
],
orderByColumn: 1,
first: 10
}) {
headers
rows
pageInfo {
startCursor
endCursor
hasNextPage
hasPreviousPage
}
}
}
{
"data": {
"metricReport": {
"headers": [
"restaurant_name",
"taco_name",
"Revenue",
"Taco Order Count"
],
"rows": [
["El Buen Sabor", "Carne Asada", "2754", "789"],
["El Buen Sabor", "Al Pastor", "2251", "681"],
["El Buen Sabor", "Fish", "2105", "623"],
["Sabor Mexicano", "Shrimp", "2031", "598"],
["Taco Fiesta", "Barbacoa", "1987", "564"],
["Sabor Mexicano", "Chorizo", "1890", "530"],
["Taco Fiesta", "Pollo", "1782", "482"],
["El Buen Sabor", "Veggie", "1542", "377"],
["Sabor Mexicano", "Breakfast", "1523", "412"],
["Taco Fiesta", "Carnitas", "1345", "321"]
],
"pageInfo": {
"startCursor": "eyJvZmZzZXQiOjB9",
"endCursor": "eyJvZmZzZXQiOjl9",
"hasNextPage": true,
"hasPreviousPage": false
}
}
}
}
Top Values​
The Top Values API returns an array of the most frequent non-null values in a given column.
- Query
- Response
query {
topValues(input: {
dataPool: {
name: "TacoSoft Demo Data"
},
columnName: "taco_name",
timeRange: {
relative: THIS_YEAR
},
maxValues: 5
}) {
values
}
}
{
"topValues": {
"values": [
"Breakfast",
"Veggie",
"Shrimp",
"Chorizo",
"Barbacoa"
]
}
}
How to test your GraphQL query​
Once you have a GraphQL query for your data that you want to test, there are a few ways to go about it.
1. GraphQL Explorer​
You can check out our GraphQL Explorer, log in to your Propel account, and test your query there.
2. cURL or a similar tool​
If you'd like to test your query with curl or a similar tool, you can first create an access token like so:
curl -X POST https://auth.us-east-2.propeldata.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET"
You can find your client ID and secret on Propel Console in the Applications page.
Once you have your access token, you can use it to test your query like this:
curl -X POST https://api.us-east-2.propeldata.com/graphql \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"query": "query LeaderboardExample1($input: LeaderboardInput!) { leaderboard(input: $input) { headers rows }}",
"variables": {
"input": {
"metricName": "Revenue",
"sort": "DESC",
"timeRange": {
"relative": "LAST_N_DAYS",
"n": 30
},
"rowLimit": 10,
"dimensions": [
{
"columnName": "restaurant_name"
}
],
"filters": []
}
}
}'
3. JavaScript​
Here's an example of how you can run a GraphQL query using fetch
in vanilla JavaScript.
const query = `
query LeaderboardExample1($input: LeaderboardInput!) {
leaderboard(input: $input) {
headers
rows
}
}
`
const variables = {
input: {
metricName: 'Revenue',
sort: 'DESC',
timeRange: {
relative: 'LAST_N_DAYS',
n: 30
},
rowLimit: 10,
dimensions: [{ columnName: 'restaurant_name' }],
filters: []
}
}
// Fetch access token
fetch('https://auth.us-east-2.propeldata.com/oauth2/token', {
method: 'post',
body: `grant_type=client_credentials&client_id=${process.env.CLIENT_ID}&client_secret=${process.env.SECRET}`
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
})
.then((response) => response.json())
.then((jsonData) => jsonData.access_token)
// Post the GraphQL query
.then((access_token) => {
return fetch('https://api.us-east-2.propeldata.com/graphql', {
method: 'POST',
headers: {
Authorization: `Bearer ${access_token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query, variables })
})
})
.then((response) => response.json())
.then((data) => console.log(data))
In production code, make sure not to expose your client ID and secret on the frontend.
For a more comprehensive example that shows you the whole flow from creating an OAuth 2.0 client, obtaining an access token, and running and processing a GraphQL query, you can check Propel Next.js Starter App.