GraphQL Queries

Learn how to query your content using GraphQL with the Contensa.ai SDK

What is GraphQL?

GraphQL is a query language that lets you request exactly the data you need. Unlike REST, you specify which fields you want in the response, making it more efficient.

const sdk = new MybeSDK({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.yoursite.com/v1/api/v1'
});

const result = await sdk.graphql(
  PROJECT_ID,
  `query {
    blog-postCollection {
      items {
        id
        slug
        data {
          title
          content
        }
      }
    }
  }`
);

How to Get Field Names

  1. Go to Dashboard → Content Model → Select your content type
  2. Hover over any field name and click the copy icon to copy individual field names
  3. Or click the menu (⋮) → "Copy GraphQL Fields" to copy all fields at once
  4. Paste the field names into your GraphQL query

Understanding Field Types

Different field types require different query syntax. Here's how to query each type:

1. Regular Fields (Text, Number, Boolean, Date)

Different field types require different query syntax. Here's how to query each type:

query {
  blog-postCollection {
    items {
      data {
        title          # Text field
        content        # Rich text field
        publishedDate  # Date field
        viewCount      # Number field
        isPublished    # Boolean field
      }
    }
  }
}

2. Reference Fields (Single Reference)

Reference fields point to another content entry. They return a ContentEntry type where data is a JSON scalar.

Wrong
query {
  blog-postCollection {
    items {
      data {
        title
        author {
          id
          slug
          data {  # ❌ Error!
            name
            email
          }
        }
      }
    }
  }
}

Error: Field "data" must not have a selection since type "JSON" has no subfields

Correct
query {
  blog-postCollection {
    items {
      data {
        title
        author {  # ✅ Query data as scalar
          id
          slug
          data  # Returns full JSON object
        }
      }
    }
  }
}

The data field returns the entire JSON object with all author fields

3. References-Many Fields (Array of References)

These fields return an array of ContentEntry objects. Query data as a scalar to get the full JSON.

query {
  blog-postCollection {
    items {
      data {
        title
        categories {    # Array of references
          id
          slug
          data  # Returns full JSON for each category
        }
        tags {          # Another array
          id
          slug
          data  # Returns full JSON for each tag
        }
      }
    }
  }
}

Each data field will contain the complete JSON object with all fields for that entry.

4. Media Fields

Media fields return file information and need subfield selection.

query {
  blog-postCollection {
    items {
      data {
        title
        featuredImage {    # Media field
          id
          filename
          url
          mimeType
          size
        }
      }
    }
  }
}

Complete Example

Here's a real-world example combining all field types:

const sdk = new MybeSDK({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.yoursite.com/v1/api/v1'
});

const PROJECT_ID = 'your-project-id';

const result = await sdk.graphql(
  PROJECT_ID,
  `query {
    blog-postCollection(limit: 10) {
      items {
        id
        slug
        status
        contentType {
          id
          name
          slug
        }
        data {
          # Regular fields
          title
          content
          publishedDate
          viewCount
          
          # Reference field (single)
          # Returns ContentEntry where data is a JSON scalar
          author {
            id
            slug
            data  # Gets full author JSON: { name, email, bio, ... }
          }
          
          # References-many field (array)
          # Each item is a ContentEntry with data as JSON scalar
          categories {
            id
            slug
            data  # Gets full category JSON: { categoryName, ... }
          }
          
          # Media field
          featuredImage {
            id
            url
            filename
          }
        }
        created_at
        updated_at
      }
      total
    }
  }`
);

console.log(result);

Using Variables

Variables make your queries dynamic and reusable:

const result = await sdk.graphql(
  PROJECT_ID,
  `query GetPosts($status: String!, $limit: Int!) {
    blog-postCollection(
      where: { status: $status }
      limit: $limit
    ) {
      items {
        id
        slug
        data {
          title
        }
      }
      total
    }
  }`,
  { 
    status: "published",
    limit: 10 
  }
);

Filtering Content

Use the where clause to filter results:

// Filter by slug
query {
  blog-postCollection(where: { slug: "my-first-post" }) {
    items {
      id
      data { title }
    }
  }
}

// Filter by status
query {
  blog-postCollection(where: { status: "published" }) {
    items {
      id
      data { title }
    }
  }
}

// Filter by locale
query {
  blog-postCollection(where: { locale: "en-US" }) {
    items {
      id
      locale
      data { title }
    }
  }
}

// Filter by custom field (with variables)
query GetByCategory($categoryName: String!) {
  blog-postCollection(where: { category: $categoryName }) {
    items {
      data { title }
    }
  }
}

Filtering by Locale

Filter content by locale to retrieve entries in specific languages. This is useful for building multilingual applications where you need to fetch content in a particular language.

// Get all Bangla (Bengali) content
query {
  blog-postCollection(where: { locale: "bn-BD" }) {
    items {
      id
      locale
      slug
      data {
        title
        content
      }
    }
    total
  }
}

// Get all English content
query {
  blog-postCollection(where: { locale: "en-US" }) {
    items {
      id
      locale
      data { title }
    }
  }
}

// Combine locale with status filter
// Get only published content in a specific locale
query {
  blog-postCollection(
    where: { 
      locale: "bn-BD"
      status: "published" 
    }
  ) {
    items {
      id
      locale
      status
      data {
        title
      }
      published_at
    }
  }
}

// Using variables for dynamic locale filtering
query GetByLocale($locale: String!, $status: String!) {
  blog-postCollection(
    where: { 
      locale: $locale
      status: $status
    }
    limit: 10
  ) {
    items {
      id
      locale
      status
      data {
        title
        content
      }
    }
    total
  }
}

// Example usage with the SDK:
const result = await sdk.graphql(
  PROJECT_ID,
  `query GetByLocale($locale: String!, $status: String!) {
    blog-postCollection(
      where: { 
        locale: $locale
        status: $status
      }
    ) {
      items {
        id
        locale
        data { title }
      }
    }
  }`,
  { 
    locale: "bn-BD",
    status: "published"
  }
);

Locale Codes

Common locale codes follow the format language-REGION:

  • en-US - English (United States)
  • bn-BD - Bangla (Bangladesh)
  • es-ES - Spanish (Spain)
  • fr-FR - French (France)
  • de-DE - German (Germany)

Pagination

Control how many items are returned and skip items:

// Get first 10 items
query {
  blog-postCollection(limit: 10) {
    items { id }
    total
  }
}

// Skip first 10, get next 10 (page 2)
query {
  blog-postCollection(limit: 10, skip: 10) {
    items { id }
    total
    limit
    skip
  }
}

Common Errors & Solutions

Error: "must not have a selection since type JSON has no subfields"

Cause: You're trying to query subfields of data on a reference field, but reference fields return ContentEntry where data is a JSON scalar.

Solution: Query data without curly braces:

# Wrong
author {
  id
  data {
    name  # ❌ Can't query subfields
  }
}

# Correct
author {
  id
  slug
  data  # ✅ Returns full JSON: { name, email, ... }
}

Error: "must have a selection of subfields"

Cause: You're trying to query a reference or media field without specifying any subfields.

Solution: Add subfields inside curly braces:

# Wrong
author  # ❌ No subfields

# Correct
author {
  id
  slug
  data
}

Error: "Cannot query field 'fieldName'"

Cause: The field name doesn't exist in your content type.

Solution: Check your field names in the dashboard and copy them using the copy button.

💡 Pro Tips

  • Always include contentType.slug to know which content type each entry belongs to
  • Use the dashboard's "Copy GraphQL Fields" button to avoid typos
  • Reference fields return ContentEntry objects - query data as a scalar (no curly braces) to get the full JSON
  • Regular fields on your main content type have structured data - you can query specific subfields
  • Start with simple queries and add fields incrementally
  • Use variables for dynamic values instead of hardcoding them