Response
The Monday::Response class wraps HTTP responses from the monday.com API.
Overview
Every request to monday.com returns a Monday::Response object that encapsulates the HTTP response status, parsed JSON body, and headers. This wrapper provides convenient access to response data and helps detect errors.
All resource methods (client.board.query, client.item.create, etc.) return a Monday::Response object.
Attributes
All attributes are read-only (attr_reader).
| Attribute | Type | Description |
|---|---|---|
status | Integer | HTTP status code (200, 400, 401, 404, 500, etc.) |
body | Hash | Parsed JSON response body containing GraphQL data |
headers | Hash | HTTP response headers as key-value pairs |
Example:
response = client.board.query(args: { ids: [123] })
response.status # => 200
response.body # => { "data" => { "boards" => [...] } }
response.headers # => { "content-type" => "application/json", ... }Methods
success?
Determines if the request was successful.
response.success? # => true or falseReturns: Boolean
monday.com API Quirk
monday.com returns HTTP 200 status codes even for some GraphQL errors. The success? method checks BOTH the status code (200-299) AND the response body for error keys.
Error Detection:
The method returns false if:
- HTTP status code is outside 200-299 range, OR
- Response body contains any of these keys:
"errors","error_code","error_message"
Example:
response = client.board.query(args: { ids: [123] })
if response.success?
# Safe to access data
boards = response.body.dig("data", "boards")
else
# Handle error
errors = response.body["errors"]
endResponse Structure
Successful GraphQL Response
All successful GraphQL responses follow this structure:
{
"data" => {
"boards" => [
{ "id" => "123", "name" => "My Board" }
]
},
"account_id" => 12345678
}The actual data is nested under the "data" key, with the resource name as the next level.
Common GraphQL response patterns:
| Operation | Path to data |
|---|---|
| Query boards | response.body.dig("data", "boards") |
| Create board | response.body.dig("data", "create_board") |
| Query items | response.body.dig("data", "items") |
| Create item | response.body.dig("data", "create_item") |
| Duplicate board | response.body.dig("data", "duplicate_board", "board") |
Error Response
Error responses contain an "errors" array:
{
"errors" => [
{
"message" => "User unauthorized to perform action",
"extensions" => {
"code" => "AuthorizationException",
"error_code" => "AuthorizationException"
}
}
],
"account_id" => 12345678
}Alternative error formats:
# Simple error
{
"error_message" => "Invalid token",
"error_code" => "InvalidTokenException"
}
# Generic error
{
"errors" => "Some error message"
}Accessing Data
Using dig for Safe Access
Always use dig to safely navigate nested response data:
response = client.board.query(args: { ids: [123] })
# Safe - returns nil if any key is missing
boards = response.body.dig("data", "boards")
# Unsafe - raises error if key is missing
boards = response.body["data"]["boards"] # Don't do thisAccessing Nested Data
Single board:
response = client.board.query(args: { ids: [123] })
boards = response.body.dig("data", "boards")
board = boards&.first
puts board["name"] # => "My Board"
puts board["id"] # => "123"Board with items:
response = client.board.query(
args: { ids: [123] },
select: ["id", "name", { items: ["id", "name"] }]
)
board = response.body.dig("data", "boards", 0)
items = board["items"]
items.each do |item|
puts item["name"]
endPaginated items:
response = client.board.items_page(
board_ids: 123,
limit: 50
)
items_page = response.body.dig("data", "boards", 0, "items_page")
items = items_page["items"]
cursor = items_page["cursor"]
puts "Retrieved #{items.length} items"
puts "Next cursor: #{cursor}"Handling Missing Data
response = client.board.query(args: { ids: [999] })
boards = response.body.dig("data", "boards")
if boards.nil? || boards.empty?
puts "No boards found"
else
puts "Found #{boards.length} boards"
endError Responses
Checking for Errors
response = client.board.query(args: { ids: [123] })
unless response.success?
if response.body["errors"]
errors = response.body["errors"]
errors.each do |error|
puts "Error: #{error['message']}"
end
elsif response.body["error_message"]
puts "Error: #{response.body['error_message']}"
end
endError Response Examples
Authorization Error (HTTP 200 with errors in body):
{
"errors" => [
{
"message" => "User unauthorized to perform action",
"extensions" => {
"code" => "AuthorizationException"
}
}
],
"account_id" => 12345678
}
response.status # => 200
response.success? # => false (because errors key exists)Invalid Token (HTTP 401):
{
"error_message" => "Invalid token",
"error_code" => "InvalidTokenException"
}
response.status # => 401
response.success? # => falseRate Limit (HTTP 429):
{
"error_message" => "You have reached the rate limit",
"error_code" => "ComplexityException"
}
response.status # => 429
response.success? # => falseInvalid Query (HTTP 200 with errors in body):
{
"errors" => [
{
"message" => "Field 'invalid_field' doesn't exist on type 'Board'",
"locations" => [{ "line" => 1, "column" => 20 }]
}
]
}
response.status # => 200
response.success? # => false (because errors key exists)Usage Examples
Basic Query
response = client.board.query(args: { ids: [123] })
if response.success?
boards = response.body.dig("data", "boards")
puts "Found #{boards.length} boards"
else
puts "Request failed with status #{response.status}"
endCreate Operation
response = client.board.create(
args: {
board_name: "New Board",
board_kind: :public
}
)
if response.success?
board = response.body.dig("data", "create_board")
puts "Created board #{board['id']}: #{board['name']}"
else
errors = response.body["errors"]
puts "Failed to create board: #{errors}"
endHandling Nested Data
response = client.item.query(
args: { ids: [456] },
select: ["id", "name", { column_values: ["id", "text", "value"] }]
)
if response.success?
items = response.body.dig("data", "items")
item = items&.first
if item
puts "Item: #{item['name']}"
column_values = item["column_values"]
column_values&.each do |cv|
puts " #{cv['id']}: #{cv['text']}"
end
end
endChecking Response Headers
response = client.board.query(args: { ids: [123] })
puts "Status: #{response.status}"
puts "Content-Type: #{response.headers['content-type']}"
puts "Rate Limit: #{response.headers['x-ratelimit-remaining']}"Processing Multiple Results
response = client.board.query(
args: { ids: [123, 456, 789] }
)
if response.success?
boards = response.body.dig("data", "boards") || []
boards.each do |board|
puts "Board #{board['id']}: #{board['name']}"
end
puts "\nTotal: #{boards.length} boards"
else
puts "Failed to fetch boards"
endBest Practices
Always Check success?
Never assume a request succeeded. Always check before accessing data:
# Good
response = client.board.query(args: { ids: [123] })
if response.success?
boards = response.body.dig("data", "boards")
# Work with boards
else
# Handle error
end
# Bad - will raise error if request fails
boards = client.board.query(args: { ids: [123] }).body["data"]["boards"]Use dig for Safe Navigation
Use dig to safely access nested data:
# Good - returns nil if any key is missing
board = response.body.dig("data", "boards", 0)
name = board&.dig("name")
# Bad - raises error if key is missing
name = response.body["data"]["boards"][0]["name"]Handle nil Results
Always check for nil before iterating:
# Good
boards = response.body.dig("data", "boards") || []
boards.each { |board| puts board["name"] }
# Or
boards = response.body.dig("data", "boards")
if boards
boards.each { |board| puts board["name"] }
end
# Bad - raises error if boards is nil
boards = response.body.dig("data", "boards")
boards.each { |board| puts board["name"] }Store Response Data
Extract data from the response before working with it:
# Good
response = client.board.query(args: { ids: [123] })
if response.success?
boards = response.body.dig("data", "boards")
# Now work with boards array
end
# Less efficient - accessing response.body multiple times
if response.success?
response.body.dig("data", "boards").each do |board|
# ...
end
endCheck Both success? and Data Presence
Some queries may succeed but return empty results:
response = client.board.query(args: { ids: [999] })
if response.success?
boards = response.body.dig("data", "boards")
if boards && !boards.empty?
# Process boards
else
puts "No boards found with ID 999"
end
else
puts "Request failed: #{response.status}"
endGraphQL Response Format
Data Wrapper
All successful GraphQL responses wrap data in a "data" key:
{
"data" => {
# Actual response data here
},
"account_id" => 12345678
}Query Responses
Query responses use plural resource names:
# boards query
{
"data" => {
"boards" => [...]
}
}
# items query
{
"data" => {
"items" => [...]
}
}Mutation Responses
Mutation responses use the mutation name:
# create_board
{
"data" => {
"create_board" => { "id" => "123", "name" => "New Board" }
}
}
# update_board (returns JSON string)
{
"data" => {
"update_board" => '{"success":true,"undo_data":"..."}'
}
}
# duplicate_board (nested under "board")
{
"data" => {
"duplicate_board" => {
"board" => { "id" => "456", "name" => "Duplicated Board" }
}
}
}Error Structure
Errors use the "errors" array:
{
"errors" => [
{
"message" => "Error description",
"extensions" => {
"code" => "ErrorCode"
}
}
],
"account_id" => 12345678
}Related Documentation
- Client - Making API requests
- Error Handling - Handling exceptions
- Board Resource - Example resource usage
- Item Resource - Example resource usage