How to use Galley's GraphQL API to access and edit the data in your account.
Overview
This article provides a comprehensive guide to using Galley's GraphQL Open API, with a focus on querying recipes and menus using connection API calls. The manual includes step-by-step instructions and examples to help you get started with the API, leveraging the GraphQL playground for exploration and testing.
Getting Started
The Galley GraphQL API is accessible via HTTPS POST at https://api.galleysolutions.com/graphql. There is a GraphQL Playground available at the same URL that you can use in your browser to execute queries against the API.
Authentication & Authorization
Galley supports two types of API keys that can be used for authentication. The same key can be used to make requests to both the Production and Staging environments.
1. Full-access, Read & Write Keys
These keys use an x-api-key
header to authenticate and have admin-level permissions, meaning you can execute all mutations and queries available to a normal admin user in the web-app.
2. User-scoped, Read-only Keys
These keys use an x-user-api-key
header to authenticate, and have admin-level, but read-only, permissions.
Your key should be the only additional header provided in the API POST request, formatted as:
{ “x-api-key”: “<your api key>” }
OR
{ “x-user-api-key”: “<your api key>” }
Please reach out to support@galleysolutions.com or in the in-app chat to obtain your API key. Keys can be refreshed upon request.
Rate Limits
To ensure the quality and stability of Galley's services, rate limiting is enforced on calls to the Galley API. The limit is set to 600 requests per 5-minute period from each unique IP address.
Exceeding the allotment will result in a 403 response with the message "This request had been blocked due to rate limits." If the error is received, please wait to make additional requests until the appropriate amount of time has passed and try again.
When writing a script that may exceed this number of requests, we recommend implementing a delay of 0.5 seconds between each request to ensure the limit is not reached.
Pagination
The API enforces pagination limits with a max size of 25 results per page on most API queries. This includes viewer.recipeConnection
, viewer.menuConnection
and any other connection
query. The examples below show how the paginationOptions
argument can be used to easily loop through all results.
Any script using one of the queries above with a limit greater than 25 will result in an error while any script without a limit set will automatically have a limit of 25.
UUIDs
Galley uses UUIDs to uniquely identify entities in the system. Every entity has an id
field that can be considered unique. UUIDs are not expected to change once an entity is created, and users will be notified in advance if there is going to be a change.
In the web app, you can determine the UUID of an entity from the URL. For example, if you've clicked into a specific menu, the UUID of the menu would be in the URL as /menus/<uuid of menu>
.
Error Handling
Most mutations have an optional error
field that can be requested when making API calls. If an error occurs from the call, the error.message
can provide additional detail into the cause.
Support Tools
Production & Staging Playgrounds
- Production Environment: Access the production GraphQL playground at https://api.galleysolutions.com/graphql.
- Staging Environment: Access the staging GraphQL playground at https://staging-api.galleysolutions.com/graphql. (Learn more)
- Navigate to the appropriate URL (production or staging).
- Use the left pane to write your GraphQL queries.
- Click the "Play" button to execute the query.
- View the response in the right pane.
In-App Queries
All functionality within the Galley web-app is powered by the GraphQL API. You can freely inspect all GraphQL requests the web app makes to learn how to replicate the functionality with API calls.
Domain Visualization
We also have a visualization of the Galley domain to help you navigate the playground docs.
Common Queries
recipeConnection
Recipes are a core component of the Galley API. The recipeConnection
API call allows you to retrieve a paginated list of recipes efficiently, which is particularly useful when dealing with large datasets.
Query:
query fetchAllRecipes($paginationOptions: PaginationOptions) {
viewer {
recipeConnection(paginationOptions: $paginationOptions) {
edges {
node {
id
name
totalYield
yieldUnit {
id
name
}
}
}
totalCount
pageInfo {
hasNextPage
startIndex
endIndex
}
}
}
}
Variables:
{
"paginationOptions": {
"first": 25,
"startIndex": 0
}
}
Sample Response:
{
"data": {
"viewer": {
"recipeConnection": {
"edges": [
{
"node": {
"id": "cmVjaXBlOjcxMTgwNA==",
"name": "Guacamole",
"totalYield": 3900,
"yieldUnit": {
"id": "dW5pdDox",
"name": "g"
}
}
},
//... 24 more recipes
],
"totalCount": 33,
"pageInfo": {
"hasNextPage": true,
"startIndex": 0,
"endIndex": 25
}
}
}
}
}
menuConnection
Menus are collections of recipes grouped together. Similar to recipes, you can use connection API calls to retrieve a paginated list of menus using the menuConnection
query.
You can also use the filters
on any connection call to filter down the list to specific results.
Query:
query fetchLunchMenus($paginationOptions: PaginationOptions, $filters: MenuConnectionFilter) {
viewer {
menuConnection(paginationOptions: $paginationOptions, filters: $filters) {
edges {
node {
id
name
menuItems {
recipe {
name
}
volume
unit {
id
name
}
}
}
}
totalCount
pageInfo {
hasNextPage
startIndex
endIndex
}
}
}
}
Variables:
{
"paginationOptions": {
"first": 25,
"startIndex": 0
},
"filters": {
"categoryValueIdsBooleanExpressionFilterJSON": {
"and": ["<category value id>"]
}
}
}
Sample Response:
{
"data": {
"viewer": {
"menuConnection": {
"edges": [
{
"node": {
"id": "bWVudTo0MTIyODA1",
"name": "Lunch - Entree",
"menuItems": [
{
"recipe": {
"name": "Lemon Quinoa Salad with Chicken"
},
"volume": 100,
"unit": {
"id": "dW5pdDoyNDI5NzA3",
"name": "serving"
}
},
{
"recipe": {
"name": "Chicken Caesar Salad"
},
"volume": 100,
"unit": {
"id": "dW5pdDoyNDI5NzA4",
"name": "serving"
}
},
{
"recipe": {
"name": "Club Soda"
},
"volume": 100,
"unit": {
"id": "dW5pdDoyNDI5ODc4",
"name": "can"
}
}
]
}
},
//... 2 more menus
],
"totalCount": 3,
"pageInfo": {
"hasNextPage": false,
"startIndex": 0,
"endIndex": 2
}
}
}
}
}
Common Mutations
upsertRecipe
The GraphQL API can also be used to send data to your Galley account. The upsertRecipe
mutation is a common way to create or update recipe fields.
Mutation:
mutation updateRecipeMutation($input: UpsertRecipeInput!) {
upsertRecipe(input: $input) {
recipe {
id
name
shelfLifeDays
}
error {
message
}
}
}
Input:
{
"input": {
"recipe": {
"id": "<recipe id>",
"shelfLifeDays": <integer value>
}
}
}
Sample Response:
{
"data": {
"upsertRecipe": {
"recipe": {
"id": "cmVjaXBlOjcxMjA4OA==",
"name": "Brazilian Cheese Bread (Pão de Queijo)",
"shelfLifeDays": 3
},
"error": null
}
}
}
bulkAddCategoryValueItem
Bulk mutations can be useful when trying to write values to multiple entities at once. For example, the bulkAddCategoryValueItem mutation can be used to bulk tag multiple entities with the same category tag(s).
Mutation:
mutation BulkAddCategoryValueItems($input: BulkAddCategoryValueItemsInput!) {
bulkAddCategoryValueItems(input: $input) {
categoryValueItems {
itemId
itemType
categoryValue {
name
}
}
error {
message
}
}
}
Input:
{
"input": {
"itemIds": ["<menu 1 id>", "<menu 2 id>", "<menu 3 id>"],
"categoryValueIds": ["<category value 1 id>", "<category value 2 id>"],
"itemType": "menu"
}
}
Sample Response:
{
"data": {
"bulkAddCategoryValueItems": {
"categoryValueItems": [
{
"itemId": "bWVudTo0MTIyODA3",
"itemType": "menu",
"categoryValue": {
"name": "buffet"
}
},
{
"itemId": "bWVudTo0MTIyODA3",
"itemType": "menu",
"categoryValue": {
"name": "lunch"
}
},
// ... 4 more category value items
],
"error": null
}
}
}