Error Handling & Best Practices

Error Handling

When querying the GraphQL API, you may encounter error responses. Errors are returned in the standard GraphQL error format (with an "errors" array in the JSON response). Here are some common error scenarios and how to address them:

  • Authentication/Authorization Errors: If you do not provide a valid API key or token, or if it’s expired or revoked, the request will be rejected. In many cases, you will receive an HTTP 401 Unauthorized response. Ensure that the Authorization or X-Buildbetter-API-Key header is present and correct. If you see an error like "Not authorized" or a similar message, double-check your credentials. Also, if you are using a shared link key, make sure you are querying the specific allowed data (for example, a shared document key cannot be used to fetch a different document).
  • Permission Denied (Forbidden): Even with a valid login, you might try to access data you aren’t allowed to. For example, querying a call ID that belongs to a different organization or a field that your role cannot see. In this case, the API might return a 403 Forbidden or an error message in the GraphQL errors indicating lack of permissions. For instance, you might get an error: "permission denied for table 'interview'" if you tried to access a resource outside your scope. The solution is to ensure you’re querying IDs that belong to your organization or have the proper share key for that object. If you believe you should have access, check that your user has the necessary permissions in the BuildBetter app (or contact an admin).
  • Query Validation Errors: If your GraphQL syntax is incorrect or you request a field that doesn’t exist, the API will return a validation error. For example, `“Cannot query field ‘foobar’ on type ‘interview’”. These indicate mistakes in the query. Double-check field names against the documentation or introspection. Similarly, if you use a variable but forget to include it or mismatch types (e.g., passing a string where a bigint is expected), you’ll get a descriptive error. Resolving these usually involves fixing typos or adjusting your query to match the schema.
  • Complexity/Depth Errors: The BuildBetter API has limits on query complexity to protect performance. Extremely nested or large queries can be rejected. Internally, the system calculates the query depth and number of nodes, and if these exceed certain thresholds (approximately depth > 100 or nodes > 1000 by default) the API will refuse to execute the query. In such cases, you might see an error message like: “Query is too complex”. To resolve this, simplify your query – for example, fetch less nested data or split the query into multiple smaller queries. Most typical queries will be far under these limits, but if you are auto-generating very deep queries (or fetching huge nested relationships in one go), be mindful of this limit. Best practice is to only request the data you truly need.
  • Rate Limiting or Server Errors: While not usually an issue, if you send a very high volume of requests, you could run into rate limiting. The API might respond with a 429 Too Many Requests or a message indicating you should slow down. If you encounter this, implement exponential backoff or contact BuildBetter support for higher rate limits. For server-side errors (HTTP 500), these are rare and usually indicate an internal issue – you can retry the query after some time, and if it persists, reach out to support.

In all cases, the "errors" array in the response will contain message fields that guide you to the problem. During development, using a GraphQL client or IDE can help catch errors early (for example, GraphiQL or Apollo Studio will underline unknown fields or type mismatches). By carefully reading error messages and following the documentation, you can resolve most issues quickly.

Best Practices

To make the most efficient use of the GraphQL API and ensure smooth operation, consider the following best practices:

  • Request Only What You Need: GraphQL lets you specify exact fields. Avoid requesting large blocks of data if you don’t need them. This reduces payload size and speeds up queries. For example, if you only need call names and IDs for a list view, query just those fields, not the entire transcript or all attendees.

  • Use Filters and Pagination: When dealing with potentially large datasets (e.g., hundreds of calls or signals), use the where filters and pagination parameters (limit and offset) to limit how much data is returned. Fetch data in chunks rather than one huge query. For instance, to get calls in pages of 50, you can query interview(limit: 50, offset: 0) for the first page, then offset: 50 for the next, and so on. Similarly, filter by date or other criteria to narrow results if applicable (e.g., only calls after a certain date).

  • Leverage GraphQL Fragments: If you find yourself writing the same selection of fields in multiple queries, use GraphQL fragments to define that set of fields once and reuse it. This makes your queries cleaner and ensures consistency. For example, you might define a fragment for basic call info:

    fragment CallBasicFields on interview {
      id
      name
      started_at
      completed_at
    }
    

    Then use ...CallBasicFields in any query where you need those fields. Fragments are especially useful if your application has predefined data patterns (the BuildBetter frontend uses fragments to keep field selections consistent across different queries for calls, signals, etc. ).

  • Avoid Excessive Nesting: As mentioned, extremely deep queries can hit complexity limits. While GraphQL can fetch related data in one go, try not to nest too many relationship levels in one query if not necessary. For example, pulling a call -> its attendees -> each attendee’s user -> each user’s organization -> etc., in one query is probably overkill and might be denied. Instead, fetch the call and attendees first, then if you need more info about a user or org, use a follow-up query (or design your schema usage such that you request what you need in a manageable shape).

  • Use Order-By and Aggregations for Efficiency: The API supports sorting (order_by) and basic aggregations. If you need the data sorted or some aggregate like count, let the server do it if possible, instead of retrieving everything and sorting on the client. For example, use order_by: { created_at: desc } rather than fetching unsorted data and ordering in your code. To get a count of items, you can use the _aggregate fields that Hasura provides (for instance, interview_aggregate { aggregate { count } } will return the number of calls). This prevents you from fetching all records just to count them.

  • Respect Rate Limits and Timeouts: Design your integration to be respectful of the API. Do not spam the server with rapid-fire requests; if you need to fetch a lot of data, page through it with delays as needed. The server may enforce rate limits. Also, network calls have timeouts – very large queries might time out, so it’s another reason to break them into smaller pieces using pagination or targeted queries.

  • Secure Your API Keys: If you are using API keys, treat them like passwords. Do not embed them in client-side code or share them publicly. If you need to call the GraphQL API from a client application (like a single-page app), it’s better to use the user’s JWT (via the Authorization header) after they log in, rather than a master API key. API keys are best used in secure server environments.

  • Monitor Query Performance: In a production environment, keep an eye on how long your queries take and how much data they return. GraphQL makes it easy to ask for a lot, but always consider the end-user experience. If a query is slow (for example, fetching a call with thousands of transcript segments and signals in one go), you might want to load parts of the data on demand (e.g., lazy-load the transcript when a user opens a call detail view, instead of in the initial query).

By following these best practices, you’ll ensure that your integration with BuildBetter’s GraphQL API is efficient, reliable, and secure. The API is quite powerful, allowing you to retrieve rich data (calls with transcripts, signals with context, documents with their source) in flexible ways. Use that power judiciously and your application will provide a great experience without running into limits or issues.

Finally, remember that the BuildBetter documentation and schema are your friends. If you’re unsure about a field or type, refer back to this guide or use schema introspection to get details. Happy querying!