GraphQL operations
How an operation is added to the package, or changed. The reasoning is in 0003; this page is the procedure.
The files, the enum naming them and the loader shipped with #7, and the check against the schema with #9.
The standard schema, tests/Resources/schema.graphql, is introspected from the live API (2026-09-21), with tests/Resources/introspection.json beside it. The Corporate one is still assembled from the documentation: its endpoint answers no_enterprise_access to an account without the Corporate plan, and its header says so.
Where things live
src/Resources/graphql/
├── queries/ one file per query: document.graphql, documents.graphql
├── mutations/ one file per mutation: createDocument.graphql
├── corporate/ the same two, for the Corporate endpoint
└── fragments/ shared selections: DocumentFields.graphql- One operation per file. The operation's name is the file's name:
mutations/createDocument.graphqlholdsmutation createDocument(…), and the answer arrives underdata.createDocument. - Variables are named after the argument they feed, snake case included:
$folder_idforfolder_id:. The array a caller's code builds then reads like the API's own documentation. - Values are variables, always (invariant 2). An operation declares every value it needs as a
$variablewith its GraphQL type. - A selection used in more than one operation is a fragment, in its own file named after it. An operation spreads it (
...DocumentFields) and the loader appends the fragment, and any fragment it spreads in turn, each once.
Adding an operation
- Write the file. Copy the operation from the Autentique documentation when it has one, turn every literal argument into a variable, and select the fields the package will model, reusing fragments where the selection already exists.
- Add the enum case to
LSNepomuceno\LaravelAutentique\GraphQL\Operation, whose value is the file's path without the extension. Whether it is a query or a mutation, which endpoint it targets and the field its answer arrives under all follow from that path. - Validate it against the schema.
tests/GraphQL/SchemaTest.phpparses and validates every file againsttests/Resources/schema.graphqlwithwebonyx/graphql-php, a development dependency only, so a misspelled field or a wrong argument type failscomposer test. If the API has something the committed schema lacks, refresh the schema first (below); never edit it to make an operation pass. - Model the answer. Every field the file selects becomes a typed property of a value object (0008). A field selected and not modelled is a field nobody can read.
- Test it with a fixture: the response the documentation shows, or one recorded from the sandbox with personal data replaced. Assert the variables sent as well as the object returned.
- Document it in the guide page for its area, and in the public API.
Enums
A package enum that mirrors an API enum (ActionEnum, DeliveryMethodEnum, …) is listed in mirroredEnums() in tests/GraphQL/SchemaTest.php, and the suite compares their values: every non deprecated value of the schema's enum, and nothing else. An enum in src/Enums that is not listed fails the suite, so a new one cannot skip the comparison.
What the suite checks today
tests/GraphQL/OperationTest.php:
- every enum case has a file and every file has a case;
- every operation is named after its file;
- every fragment is named after its file, and every fragment is used;
- no argument in any file is a literal, only a variable;
- the loader appends each fragment once, recursively, fails on a fragment no file defines, leaves inline fragments alone, and reads each file once.
tests/GraphQL/SchemaTest.php:
- every operation validates against the schema of its endpoint:
tests/Resources/schema.graphqlfor the standard one, introspected, andtests/Resources/schema-corporate.graphqlfor Corporate, assembled; - the check fails on an unknown field and on a variable of the wrong type;
- every GraphQL example in Autentique's own collections, the two Postman ones and the one its Altair build embeds, validates against the standard schema too (
tests/Resources/collections/): they are the closest thing to ground truth without a token, and a schema they refuse is wrong; - every mirrored enum has exactly the schema's non deprecated values;
- an introspection prints back into a schema the operations validate against.
Changing an operation
Selecting a new field is a minor release: the value object gains a nullable property. Removing a field, or making a nullable property required, is a major release, because the value objects are public.
Refreshing the schema
The Autentique documentation has no schema reference, so the schema is taken by introspection, which needs a valid token. It is refreshed by the maintainer, deliberately, not by CI:
- when Autentique announces a change;
- before a release;
- when an operation fails against the API while passing against the committed schema.
AUTENTIQUE_TOKEN=… vendor/bin/testbench autentique:schema --output=tests/Resources/introspection.json
composer schema:print
composer testtestbench.yaml registers the package's provider, so vendor/bin/testbench runs its commands. The token stays in the environment of that one command.
autentique:schema writes the introspection as JSON, and needs no development dependency, so it ships (the command). composer schema:print turns that JSON into tests/Resources/schema.graphql with webonyx/graphql-php, and stamps the date in its header. Commit both.
A refresh that makes an operation invalid fails the suite, which is the point: the change is seen here before a consumer's request fails.
.graphqlconfig points an IDE's GraphQL support at the same schema, so the operation files are completed and checked as they are written.