Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Graphql Laravel Package

ibexa/graphql

GraphQL server implementation for Ibexa DXP and Ibexa Open Source, providing a query API for content and platform data. Part of the Ibexa DXP package family.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — it only makes sense inside an Ibexa DXP / Ibexa OSS installation. If you're not already on Ibexa, the real entry point is composer create-project ibexa/oss-skeleton (or the DXP metapackage); ibexa/graphql then arrives as a dependency. On an existing install:

composer require ibexa/graphql
php bin/console cache:clear

The server is exposed at POST /graphql (route defined by IbexaGraphQLBundle). In a dev environment you'll typically find a GraphiQL route enabled alongside it — the fastest way to confirm what your installation actually exposes is to introspect rather than trust docs:

{ __schema { queryType { fields { name } } mutationType { fields { name } } } }

Files worth opening first, in this order:

  1. vendor/ibexa/graphql/src/bundle/Resources/config/graphql/ — the shipped schema YAML (queries, mutations, content type mappers). This is the source of truth for field names.
  2. config/packages/ — where the bundle's config lands in your project; this is where you add schema fragments and overrides.
  3. vendor/ibexa/graphql/src/bundle/Resources/config/services.yml — shows which services are tagged as resolvers and mappers, i.e. your extension surface.

Also check php bin/console list ibexa:graphql — current releases ship a schema-dump command (roughly ibexa:graphql:generate-schema) that writes the compiled schema to a file. Do that on day one and commit the output: it gives you autocomplete, and it's the artifact you feed to graphql-codegen.

First use case: a headless frontend fetching one content item by location ID for a route. The shape is always location → content → inline fragment on the content type:

query PageByLocation($locationId: Int!) {
  location(locationId: $locationId) {
    id
    urlAlias { path }
    content {
      id
      name
      ... on Article {
        title
        intro
      }
    }
  }
}

If you get data back, you've validated routing, permissions (the query runs as the current/anonymous user) and the content-type mapping in one shot.

Implementation Patterns

Two lookup styles, pick deliberately. location(locationId:) is for router-driven pages (you already resolved a path); content(contentId:) is for detail views and internal links; locations(parentLocationId:) for listing children. Content type–specific fields only exist inside inline fragments, so every query ends up as Content plus a ... on MyType block — build a fragment library (fragments/article.graphql) rather than repeating field sets.

Content types map to GraphQL types automatically. Field definitions are translated by per-field-type mappers (TextLine → String, relation fields → nested objects, image fields → uri/variation structures). You don't hand-write the schema for a content type; you influence it. For anything non-standard (a custom field type, a computed field, a renamed field), implement the bundle's FieldDefinitionMapper / FieldValueMapper contracts and register the service with the mapper tag — that's the canonical extension point and keeps the schema declarative.

Schema-level overrides go in YAML. Add your own files under the configured schema directory (typically config/graphql/) for extra queries, mutations and type extensions. Because these are merged, treat them like routes: small, named files, one concern each, and regenerate the dumped schema after every change. Config/schema changes are not hot-reloaded — cache:clear is mandatory.

Batching is the reason this isn't a REST wrapper. Resolution of nested content/fields goes through data loaders, so ten related items in one query cost roughly one repository round trip, not ten. That breaks the moment you write a custom resolver that hits the repository in a loop — inject the repository and resolve per-item lazily, or keep the resolver returning IDs and let the existing loaders do the work.

Mutations follow the draft workflow, not CRUD. Creating content yields a draft; publishing is a separate step, and version/draft IDs appear in the payload. Wrap multi-step content operations in a single PHP service exposed as one mutation rather than making the client orchestrate three mutations — it cuts round trips and keeps transaction boundaries sane.

Auth and caching are inherited from the platform. GraphQL requests run under the normal Ibexa user context: session cookie for browser clients, HTTP Basic (or your configured auth) for server-to-server. Permissions are enforced per field resolution, so a limited user gets partial data plus errors, not a 403. On the cache side, GraphQL is nearly always POST with a varying body, so the HTTP cache largely bypasses it — push caching to your client (Apollo/urql normalized cache) or a CDN keyed on the request body, and keep ttl short for anything user-specific.

Client tooling. Dump the schema in CI, run graphql-codegen against it, and you get typed hooks plus compile-time breakage when a content type field is renamed. That single step does more for day-to-day velocity than anything else here.

Gotchas and Tips

  • Dual license. The repo is BUL 2.4 or GPLv2, depending on whether you hold a DXP subscription. If you're deploying without a subscription, verify the GPL path covers your use before building on it.
  • Version alignment. ibexa/graphql must track your ibexa/core minor line (e.g. ^4.6 with core 4.6). Mismatched minors fail at container compile time with confusing schema errors. Pin it and upgrade with the platform.
  • Everything is HTTP 200. GraphQL errors arrive in the errors array with a 200 status and null in the data. Your client must inspect errors, not the status code — and in production the bundle masks internal messages unless debug is on, so log server-side rather than relying on the response body.
  • Naming normalization. Content type and field identifiers are converted to GraphQL casing; hyphens and underscores in identifiers can produce names you didn't expect. Always confirm against the dumped schema before writing queries.
  • Rich text comes back as markup, not structured data. You get an HTML/XML string and are responsible for sanitizing it client-side. Plan for that in the frontend component layer.
  • Deep nesting has no default complexity guard. A recursive relation query can be arbitrarily expensive. If you expose GraphQL to untrusted clients, add query depth/complexity limits at the server or proxy layer — the bundle won't do it for you.
  • Search/filtering is thinner than the REST/Public API. Complex filtering, facets and aggregation are better served by the PHP Public API or a custom resolver than by trying to bend the generated schema. Don't force it.
  • Debugging: use GraphiQL for shape errors, bin/console debug:container --tag=<mapper/resolver tag> to confirm your service is actually registered (silent non-registration is the #1 custom-field bug), and debug:router to verify the endpoint path in non-standard setups.
  • Upgrade habit: because the schema is generated from content types, adding a field to a content type can change the GraphQL schema. Diff the dumped schema in CI and treat unexpected diffs as review blockers.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dakiquang/laravel-oauth-refresh-lock
woda/laravel-worktrees
dalefranks/ramasite
faghy/laracashbook
roundly-consulting/google-places-for-laravel
roundly-consulting/kubernetes-api-for-laravel
roundly-consulting/plausible-for-laravel
gvp/gvp-laravel-template
metasyncsite/laravel-metasync-client
roundly-consulting/onboarding-for-laravel
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
adachsoft/changelog-linter