Best Practices

1. Batch Size Recommendations

  • Keep batches to a maximum of 50 mutations to avoid timeouts.

  • Instead of one large batch with 50+ mutations, split into smaller batches of mutations each.

mutation SmallBatch1 {
  op1: productCreateSimple(input: {...}) { __typename }
  op2: productCreateSimple(input: {...}) { __typename }
  op3: productCreateSimple(input: {...}) { __typename }
  op4: productCreateSimple(input: {...}) { __typename }
  op5: productCreateSimple(input: {...}) { __typename }
}
mutation SmallBatch2 {
  op6: productCreateSimple(input: {...}) { __typename }
  op7: productCreateSimple(input: {...}) { __typename }
  # ... continue with next batch
}
  • Focus on single resource operations per batch.

mutation BatchedMutations {
  create: productCreateSimple(
    input: {sku: "new_product", templateCode: "template"}
  ) {
    __typename
  }
  assignDescription: productAddAttributeValueTranslationsTextarea(
    input: {sku: "new_product", attributeCode: "description", translations: [{value: "Long description", language: "en_GB"}]}
  ) {
    __typename
  }
  assignShortDescription: productAddAttributeValueTranslationsTextarea(
    input: {sku: "new_product", attributeCode: "short_description", translations: [{value: "Short description", language: "en_GB"}]}
  ) {
    __typename
  }
}
  • Consider the synchronous execution nature.

2. Error Handling Strategy

  • Each mutation in a batch can succeed/fail independently, with code 200 - read responses for error information.

  • Use __typename for minimal successful response validation.

  • Implement retry logic for failed operations.

3. Aliasing for Duplicate Mutations

mutation {
  first: productAddAttributeValueTranslationsText(input: {...}) { __typename }
  second: productAddAttributeValueTranslationsText(input: {...}) { __typename }
  # Aliases required for duplicate mutation types
}

4. Efficient Data Flow

  • Use streams for bulk data reading.

query {
  productStream(first: 50, after:"<endCursor>") {
    pageInfo {
      hasNextPage
      endCursor
    }
    edges {
      node {
        sku
        attributeList {
          edges {
            node {
              attribute {
                code
              }
            }
          }
        }
      }
    }
  }
}
  • Minimize response payload size.

  • Leverage cursor-based pagination.

5. Input Object Optimization

  • Structure your input objects efficiently by grouping related fields.

mutation OptimizedAttributeAssignment {
  assignText: productAddAttributeValueTranslationsText(input: {
    sku: "product_sku"
    attributeCode: "name"
    translations: [
      {value: "English Name", language: "en_GB"},
      {value: "Polish Name", language: "pl_PL"},
      {value: "German Name", language: "de_DE"}
    ]
  }) {
    __typename
  }
}

6. API Keys

Securing Ergonode PIM API Keys

Area
Best practice
Why it matters
How to implement

Secret storage

Use environment variables or a managed secrets manager

Prevents leaks from code/repos and enables RBAC, audit, and encryption

Inject ERGONODE_API_KEY at runtime from AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, or Vault; never commit .env files

No hardcoding

Never embed keys in code, front-end, mobile, or docs

Hardcoded keys are easily leaked via repos, builds, or source maps

Enable secret scanners in CI and pre-commit; block pushes with detected patterns; review historical commits periodical

Least privilege

Scope keys per environment and integration with minimal permissions

Limits blast radius and reduces misuse risk

Separate keys for dev/stage/prod and for ERP sync, ecommerce export, DAM/analytics; prefer read-only for exports

Network restrictions

Restrict by IP/VPC/hostname where supported

Stops use from unexpected networks

Allowlist egress IPs of integration services or gateways calling Ergonode

Server-side usage

Keep keys off client devices and browsers

Client apps are untrusted; keys can be extracted

Use a backend/edge proxy to call Ergonode; clients receive only necessary data

Encryption

Enforce TLS and encrypt at rest (including backups)

Protects keys in transit and storage

HTTPS-only to Ergonode; use KMS-backed secret stores and encrypted volumes/backups

Centralization & ownership

Single source of truth with clear ownership

Avoids duplication, drift, and orphaned secrets

Maintain a key inventory: owner, purpose, scope, environment, creation/expiry

Secret scanning

Continuous scanning of code, logs, artifacts

Finds leaks quickly

Scan repos, containers, CI logs, tickets; treat any external appearance as compromise

RBAC & audits

Role-based access and regular reviews

Prevents unauthorized access; removes stale keys

Quarterly reviews; disable unused keys; least-privilege access to read/rotate secrets

Logging hygiene

Mask secrets in logs and traces

Prevents secondary leaks

Redact ERGONODE_API_KEY in app/CI logs; sanitize error payloads

Revocation (when a key may be compromised)

Step
Action
Goal
Notes

Immediate control

Disable/revoke the key ASAP

Stop further misuse

If disable is delayed, tighten scope, IP allowlists, and quotas temporarily

Replacement

Issue a new key and distribute securely

Maintain availability

Update secret manager; roll out to all services; verify traffic before final revoke

Investigation

Identify exposure vector

Prevent recurrence

Check repos, CI/CD, artifacts, screenshots, tickets, tracing/logs, container layers

Communication

Notify stakeholders and document

Coordinated response

Share migration steps, timelines; capture root cause and corrective actions

Rotation (regular, safe key changes)

Practice
Action
Benefit
Implementation tips

Policy

Rotate on schedule (e.g., 60–90 days) and on events

Limits lifetime of leaked keys

Shorter lifetimes for write/high-privilege keys

Dual-key overlap

Support new+old keys during rollout

Zero/minimal downtime

Add new key, update consumers, validate, then retire old key

Drills

Test rotation in staging

Confidence and speed

Run periodic game days; verify end-to-end behavior

By combining strict key handling (no hardcoding), managed secret storage, environment and integration scoping, continuous monitoring, and disciplined revocation/rotation, Ergonode customers can protect product data, sustain uptime, and minimize the blast radius of any credential exposure.

7. Strategies for Handling Rate Limits

Effective rate-limit handling ensures reliability and fairness when integrating with APIs. Below are pragmatic strategies to keep traffic smooth and resilient.

Exponential Backoff with Jitter

  • What it is: On receiving rate-limit responses (e.g., 429), retry after increasing delays: baseDelay × 2^attempt, plus random jitter.

  • Why it works: Spreads retries across time, avoiding thundering herds and synchronized spikes.

  • How to implement:

    • Use capped backoff (e.g., max 60s) and a max attempts threshold.

    • Prefer “full jitter” (random between 0 and current backoff) to reduce contention.

Queueing Requests

  • What it is: Buffer requests and release them at a controlled pace aligned with known limits.

  • Why it works: Smooths bursts, keeps within quotas, and avoids unnecessary failures.

  • How to implement:

    • Use per-integration queues (stage/prod) to isolate traffic.

    • Enforce concurrency caps so parallel workers don’t exceed limits collectively.

Combining Backoff and Queues

  • Queue first; if the API still returns 429 or 503, apply exponential backoff with jitter.

  • Add circuit breakers: temporarily halt dispatch if repeated rate-limit errors occur, then probe with a small number of requests.

Adaptive Throttling

  • Continuously measure success rates and latency.

  • Increase send rate cautiously when error rates are low; decrease aggressively on 429/5xx spikes.

  • Apply exponential decay to recent failures to react quickly.

Stronger Retry Policy and Control

  • Separate retry classes by failure domain:

    • Transport-level: DNS/TLS/connect timeouts, socket errors → retry with jitter.

    • HTTP-level: 429/503 honor Retry-After; 5xx apply jitter; 4xx no retry (except 409 on rare idempotent writes, if applicable).

    • GraphQL-level: retry only specific transient codes (RATE_LIMITED/TIMEOUT/SERVICE_UNAVAILABLE/INTERNAL_ERROR/THROTTLED or extensions.retriable=true).

  • Add retry budget per-call and per-process:

    • Keep max_attempts, but also enforce a per-call deadline and a global budget to prevent retry storms.

  • Include a circuit breaker:

    • If the failure ratio exceeds a threshold over a small rolling window (e.g., 50% 429/5xx in the last 20 attempts), open the breaker for a cool-off period, then half-open with probes.

By combining controlled queuing, adaptive throttling, jittered backoff, and strong observability, integrations stay within limits while maximizing throughput and reliability.

8. Schema-Aware Pre-Validation and Introspection Caching

  • Pre-flight validation:

    • Validate that mutation/query names exist against a cached introspection schema at startup. This avoids GRAPHQL_ERROR in hot paths (typos like productCreatdeSimple).

  • Introspection cache:

    • Cache the schema and refresh periodically or on a rolling schedule.

    • Optionally add a linter for common pitfalls: required variables missing, wrong scalar names, max first exceeded, and alias missing for duplicates.

  • Version pinning:

    • Snapshot the schema hash/version at deploy-time. If it changes at runtime (breaking updates), surface alerts.

9. Understanding and Avoiding the N+1 Problem in GraphQL

The N+1 problem is a performance pitfall that can make integrations slow and unpredictable, especially when fetching related data at scale. This guide explains the issue in practical terms and offers concrete best practices tailored for Ergonode PIM customers using the GraphQL API.

What is the N+1 Problem?

  • In plain terms, one request asks for a list of items (the “1”), and then the same request implicitly triggers one additional request for each item in the list (the “N”). The total work grows with the number of items retrieved.

  • Example scenario: requesting a list of products and, for each product, requesting multiple related fields (e.g., attributes, categories, multimedia). If the integration retrieves these related pieces one-by-one per product, total work scales linearly with the list size, increasing latency and resource usage.

Why it matters for Ergonode customers

  • Slower syncs and exports: large product or attribute lists combined with deeply nested fields can cause long-running jobs.

  • Unpredictable performance: the same query may be fast for small result sets and slow for larger ones.

  • Higher operational costs: inefficient access patterns increase request counts and processing time in the integration infrastructure.

  • User impact: storefronts, channels, or downstream systems, depending on timely updates, may experience delays.

Recognizing N+1 in your integration

  • Latency grows roughly with the number of items requested (doubling the list doubles the duration).

  • Logs show repeated, similar data retrieval steps per item (e.g., identical lookups for related data across all products).

  • Deeply nested selections on large lists produce inconsistent run times, especially when not using pagination.

Best practices to avoid the N+1 problem

  • Prefer stream-based pagination and sensible page sizes.

  • Use stream queries (e.g., productStream, attributeStream, categoryStream) with first and after.

  • Keep page sizes reasonable (often 50–100, per resource limits) to cap work per request.

  • Always iterate using pageInfo.hasNextPage and pageInfo.endCursor to continue efficiently.

Request only what is needed

  • Select only the fields required for the use case.

  • Avoid pulling heavy subtrees (e.g., large attribute lists, complete multimedia details) when not strictly necessary.

Flatten data access where possible

  • Prefer connection fields that already surface data in a list-friendly way (e.g., attributeList, variantList).

  • If a workflow needs multiple related pieces, try grouping them in a single, well-structured selection per page rather than repeating similar selections across multiple small calls.

Use batching in mutation workflows

  • When updating data, batch related mutations for a single resource into one request, and keep batches focused (order matters).

  • Limit batch size (aim ≤50) to reduce timeouts and make error handling predictable.

  • Use aliases for duplicate mutation types to keep results clear and avoid collisions.

Keep nested depth under control

  • Avoid deep nesting over large lists. Instead of requesting many secondary lists under each product in one go, break the work into phased steps:

    • Step 1: fetch products with essential fields.

    • Step 2: for only those requiring updates, fetch specific related slices (e.g., attributes for a shortlist of SKUs).

  • This keeps each request predictable and bounded.

Leverage targeted queries for expensive fields

  • If only a subset of items needs heavy data (e.g., galleries, large attribute sets), isolate that into a dedicated query for those items, not for every item on every page.

  • Use codes/skus captured from the stream page to drive targeted follow-ups.

Embrace idempotent, repeatable workflows

  • Design integration steps so they can safely repeat without duplicating work, enabling confident retries with smaller, more efficient selections.

  • This reduces the temptation to “fetch everything everywhere” in one pass.

Monitor and tune

  • Track average and p95/p99 durations per operation type and page size.

  • Watch for depth and breadth in selections that creep up over time (e.g., new fields added to a shared fragment).

  • Adjust page sizes and split queries when p95 grows.

Practical patterns for use cases

  • Continuous catalog sync:

    • Use productStream with a moderate first.

    • Select essential identifiers.

    • Run a targeted query to fetch the specific attributes or media required by the downstream system.

  • Attribute-driven exports:

    • Iterate attributeStream; avoid requesting full option details unless needed.

    • If options or translations are required, fetch them for the subset of attributes referenced by the current job.

  • Multimedia usage:

    • Do not fetch full multimedia objects for every product by default.

    • Resolve multimedia details only when an item requires them (e.g., newly added or updated images).

Red flags to avoid

  • Selecting the full attributeList for every product in a large page when only a few attributes are actually needed.

  • Fetching full multimedia details for all products, regardless of whether the images have changed.

  • Deep nested fields under large lists without pagination at each level.

A simple decision checklist

  • Is the selection pulling large nested data for every item? If yes, try splitting into phases.

  • Can the result be paginated at the top level? If not, can the nested lists be paginated or reduced?

  • Are only a few fields truly needed? Remove or defer the rest.

  • Does each page’s work look proportional and bounded? If not, lower first or split the query.

By structuring queries around streams and pagination, limiting nested selections, and targeting detailed lookups only when necessary, Ergonode customers can avoid the N+1 problem and keep integrations fast, reliable, and cost-effective.

Last updated

Was this helpful?