Download the PHP package convenia/graphql-laravel without Composer

On this page you can find all versions of the php package convenia/graphql-laravel. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package graphql-laravel

This repo is a fork of (Rebing Laravel GraphQL)

Latest Stable Version License Tests Downloads Get on Slack

Use Facebook's GraphQL with PHP 7.4+ on Laravel 8.0+. It is based on the PHP port of GraphQL reference implementation. You can find more information about GraphQL in the GraphQL Introduction on the React blog or you can read the GraphQL specifications.

When using the SelectFields class for Eloquent support, additional features are available:

It offers following features and improvements over the original package by Folklore:

Installation

Dependencies:

Installation:

Require the package via Composer:

Laravel

Publish the configuration file:

Review the configuration file:

Usage

Concepts

Before diving head first into code, it's good to familiarize yourself with the concepts surrounding GraphQL. If you've already experience with GraphQL, feel free to skip this part.

Typically, all queries/mutations/types are defined using the $attributes property and the args() / fields() methods as well as the resolve() method.

args/fields again return a configuration array for each field they supported. Those fields usually support these shapes

Optional keys are:

A word on declaring a field nonNull

It's quite common, and actually good practice, to see the gracious use of Type::nonNull() on any kind of input and/or output fields.

The more specific the intent of your type system, the better for the consumer.

Some examples

There exists a lot of tooling in the GraphQL ecosystem, which benefits the more specific your type system is.

Data loading

The act of loading/retrieving your data is called "resolving" in GraphQL. GraphQL itself does not define the "how" and leaves it up to the implementor.

In the context of Laravel it's natural to assume the primary source of data will be Eloquent. This library therefore provides a convenient helper called SelectFields which tries its best to eager load relations and to avoid n+1 problems.

Be aware that this is not the only way and it's also common to use concepts called "dataloaders". They usually take advantage of "deferred" executions of resolved fields, as explained in graphql-php solving n+1 problem.

The gist is that you can use any kind of data source you like (Eloquent, static data, ElasticSearch results, caching, etc.) in your resolvers but you've to be mindful of the execution model to avoid repetitive fetches and perform smart pre-fetching of your data.

Middleware Overview

The following middleware concepts are supported:

Briefly said, a middleware usually is a class:

HTTP middleware

Any Laravel compatible HTTP middleware can be provided on a global level for all GraphQL endpoints via the config graphql.route.middleware or on a per-schema basis via graphql.schemas.<yourschema>.middleware. The per-schema middleware overrides the global one.

GraphQL execution middleware

The processing of a GraphQL request, henceforth called "execution", flows through a set of middlewares.

They can be set on global level via graphql.execution_middleware or per-schema via graphql.schemas.<yourschema>.execution_middleware.

By default, the recommended set of middlewares is provided on the global level.

Note: the execution of the GraphQL request itself is also implemented via a middleware, which is usually expected to be called last (and does not call further middlewares). In case you're interested in the details, please see \Rebing\GraphQL\GraphQL::appendGraphqlExecutionMiddleware

GraphQL resolver middleware

After the HTTP middleware and the execution middleware is applied, the "resolver middleware" is executed for the query/mutation being targeted before the actual resolve() method is called.

See Resolver middleware for more details.

Schemas

Schemas are required for defining GraphQL endpoints. You can define multiple schemas and assign different HTTP middleware and execution middleware to them, in addition to the global middleware. For example:

Together with the configuration, in a way the schema defines also the route by which it is accessible. Per the default configuration of prefix = graphql, the default schema is accessible via /graphql.

Schema classes

You may alternatively define the configuration of a schema in a class that implements ConfigConvertible.

In your config, you can reference the name of the class, rather than an array.

You can use the php artisan make:graphql:schemaConfig command to create a new schema configuration class automatically.

Creating a query

First you usually create a type you want to return from the query. The Eloquent 'model' is only required if specifying relations.

Note: The selectable key is required, if it's a non-database field or not a relation

The best practice is to start with your schema in config/graphql.php and add types directly to your schema (e.g. default):

Alternatively you can:

Then you need to define a query that returns this type (or a list). You can also specify arguments that you can use in the resolve method.

Add the query to the config/graphql.php configuration file

And that's it. You should be able to query GraphQL with a request to the url /graphql (or anything you choose in your config). Try a GET request with the following query input

For example, if you use homestead:

Creating a mutation

A mutation is like any other query. It accepts arguments and returns an object of a certain type. Mutations are meant to be used for operations modifying (mutating) the state on the server (which queries are not supposed to perform).

This is conventional abstraction, technically you can do anything you want in a query resolve, including mutating state.

For example, a mutation to update the password of a user. First you need to define the Mutation:

As you can see in the resolve() method, you use the arguments to update your model and return it.

You should then add the mutation to the config/graphql.php configuration file:

You can then use the following query on your endpoint to do the mutation:

if you use homestead:

File uploads

This library uses https://github.com/laragraph/utils which is compliant with the spec at https://github.com/jaydenseric/graphql-multipart-request-spec .

You have to add the \Rebing\GraphQL\Support\UploadType first to your config/graphql schema types definition (either global or in your schema):

It is important that you send the request as multipart/form-data:

WARNING: when you are uploading files, Laravel will use FormRequest - it means that middlewares which are changing request, will not have any effect.

Note: You can test your file upload implementation using Altair as explained here.

Vue.js and Axios example
jQuery or vanilla javascript

Validation

Laravel's validation is supported on queries, mutations, input types and field arguments.

Note: The support is "sugar on top" and is provided as a convenience. It may have limitations in certain cases, in which case regular Laravel validation can be used in your respective resolve() methods, just like in regular Laravel code.

Adding validation rules is supported in the following ways:

Using the configuration key 'rules' is very convenient, as it is declared in the same location as the GraphQL type itself. However, you may hit certain restrictions with this approach (like multi-field validation using *), in which case you can override the rules() method.

Example defining rules in each argument

Example using the rules() method

Example using Laravel's validator directly

Calling validate() in the example below will throw Laravel's ValidationException which is handed by the default error_formatter by this library:

The format of the 'rules' configuration key, or the rules returned by the rules() method, follows the same convention that Laravel supports, e.g.:

For the args() method or the 'args' definition for a field, the field names are directly used for the validation. However, for input types, which can be nested and occur multiple times, the field names are mapped as e.g. data.0.fieldname. This is imported to understand when returning rules from the rules() method.

Handling validation errors

Exceptions are used to communicate back in the GraphQL response that validation errors occurred. When using the built-in support, the exception \Rebing\GraphQL\Error\ValidationError is thrown. In your custom code or when directly using the Laravel Validator, Laravel's built-in \Illuminate\Validation\ValidationException is supported too. In both cases, the GraphQL response is transformed to the error format shown below.

To support returning validation errors in a GraphQL error response, the 'extensions' are used, as there's no proper equivalent.

On the client side, you can check if message for a given error matches 'validation', you can expect the extensions.validation key which maps each field to their respective errors:

You can customize the way this is handled by providing your own error_formatter in the configuration, replacing the default one from this library.

Customizing error messages

The validation errors returned can be customised by overriding the validationErrorMessages method. This method should return an array of custom validation messages in the same way documented by Laravel's validation. For example, to check an email argument doesn't conflict with any existing data, you could perform the following:

Note: the keys should be in field_name.validator_type format, so you can return specific errors per validation type.

Customizing attributes

The validation attributes can be customised by overriding the validationAttributes method. This method should return an array of custom attributes in the same way documented by Laravel's validation.

Misc notes

Certain type declarations of GraphQL may cancel our or render certain validations unnecessary. A good example is using Type::nonNull() to ultimately declare that an argument is required. In such a case a 'rules' => 'required' configuration will likely never be triggered, because the GraphQL execution engine already prevents this field from being accepted in the first place.

Or to be more clear: if a GraphQL type system violation occurs, then no Laravel validation will be even execution, as the code does not get so far.

Resolve method

The resolve method is used in both queries and mutations, and it's here that responses are created.

The first three parameters to the resolve method are hard-coded:

  1. The $root object this resolve method belongs to (can be null)
  2. The arguments passed as array $args (can be an empty array)
  3. The query specific GraphQL context, can be customized by overriding \Rebing\GraphQL\GraphQLController::queryContext

Arguments here after will be attempted to be injected, similar to how controller methods works in Laravel.

You can typehint any class that you will need an instance of.

There are two hardcoded classes which depend on the local data for the query:

Example:

Resolver middleware

These are GraphQL specific resolver middlewares and are only conceptually related to Laravel's "HTTP middleware". The main difference:

Defining middleware

To create a new middleware, use the make:graphql:middleware Artisan command

This command will place a new ResolvePage class within your app/GraphQL/Middleware directory. In this middleware, we will set the Paginator current page to the argument we accept via our PaginationType:

Registering middleware

If you would like to assign middleware to specific queries/mutations, list the middleware class in the $middleware property of your query class.

If you want a middleware to run during every GraphQL query/mutation to your application, list the middleware class in the $middleware property of your base query class.

Alternatively, you can override getMiddleware to supply your own logic:

Terminable middleware

Sometimes a middleware may need to do some work after the response has been sent to the browser. If you define a terminate method on your middleware and your web server is using FastCGI, the terminate method will automatically be called after the response is sent to the browser:

The terminate method receives both the resolver arguments and the query result.

Once you have defined a terminable middleware, you should add it to the list of middleware in your queries and mutations.

Authorization

For authorization similar to Laravel's Request (or middleware) functionality, we can override the authorize() function in a Query or Mutation. An example of Laravel's 'auth' middleware:

Or we can make use of arguments passed via the GraphQL query:

You can also provide a custom error message when the authorization fails (defaults to Unauthorized):

Privacy

Note: this only applies when making use of the SelectFields class to query Eloquent models!

You can set custom privacy attributes for every Type's Field. If a field is not allowed, null will be returned. For example, if you want the user's email to only be accessible to themselves:

or you can create a class that extends the abstract GraphQL Privacy class:

Query variables

GraphQL offers you the possibility to use variables in your query so you don't need to "hardcode" value. This is done like that:

When you query the GraphQL endpoint, you can pass a JSON encoded variables parameter.

Custom field

You can also define a field as a class if you want to reuse it in multiple types.

You can then use it in your type declaration

Even better reusable fields

Instead of using the class name, you can also supply an actual instance of the Field. This allows you to not only re-use the field, but will also open up the possibility to re-use the resolver.

Let's imagine we want a field type that can output dates formatted in all sorts of ways.

You can use this field in your type as follows:

Eager loading relationships

The Rebing\GraphQL\Support\SelectFields class allows to eager load related Eloquent models. Only the required fields will be queried from the database.

The class can be instantiated by typehinting SelectFields $selectField in your resolve method.

You can also construct the class by typehinting a Closure. The Closure accepts an optional parameter for the depth of the query to analyse.

Your Query would look like:

Your Type for User might look like shown below. The profile and posts relations must also exist in the UserModel's relations. If some fields are required for the relation to load or validation etc, then you can define an always attribute that will add the given attributes to select.

The attribute can be a comma separated string or an array of attributes to always include.

At this point we have a profile and a post type as expected for any model

Type relationship query

Note: this only applies when making use of the SelectFields class to query Eloquent models!

You can also specify the query that will be included with a relationship via Eloquent's query builder:

Pagination

Pagination will be used, if a query or mutation returns a PaginationType.

Note that unless you use resolver middleware, you will have to manually supply both the limit and page values:

Query posts(limit:10,page:1){data{id},total,per_page} might return

Note that you need to add in the extra 'data' object when you request paginated resources as the returned data gives you the paginated resources in a data object at the same level as the returned pagination metadata.

Simple Pagination will be used, if a query or mutation returns a SimplePaginationType.

Batching

Batched requests are required to be sent via a POST request.

You can send multiple queries (or mutations) at once by grouping them together. Therefore, instead of creating two HTTP requests:

you could batch it as one

For systems sending multiple requests at once, this can help performance by batching together queries that will be made within a certain interval of time.

There are tools that help with this and can handle the batching for you, e.g. Apollo

A note on query batching: whilst it may look like an "only win" situations, there are possible downsides using batching:

  • All queries/mutations are executed in the same "process execution context".
    If your code has side-effects which might not show up in the usual FastCGI environment (single request/response), it may cause issues here.

  • The "HTTP middleware" is only executed for the whole batch once
    In case you would expect it being triggered for each query/mutation included. This may be especially relevant for logging or rate limiting.
    OTOH with "resolver middleware" this will work as expected (though the solve different problems).

  • No limitations on the number of queries/mutations
    Currently there's no way to limit this.

Support for batching can be disabled by setting the config batching.enable to false.

Scalar types

GraphQL comes with built-in scalar types for string, int, boolean, etc. It's possible to create custom scalar types to special purpose fields.

An example could be a link: instead of using Type::string() you could create a scalar type Link and reference it with GraphQL::type('Link').

The benefits would be:

This also means validation logic can be added within these methods to ensure that the value delivered/received is e.g. a true link.

A scalar type has to implement all the methods; you can quick start this with artisan make:graphql:scalar <typename>. Then just add the scalar to your existing types in the schema.

For more advanced use, please refer to the official documentation regarding scalar types.

A note on performance: be mindful of the code you include in your scalar types methods. If you return a large number of fields making use of custom scalars which includes complex logic to validate field, it might impact your response times.

Enums

Enumeration types are a special kind of scalar that is restricted to a particular set of allowed values. Read more about Enums here

First create an Enum as an extension of the GraphQLType class:

Note: within the $attributes['values'] array the key is enum value the GraphQL client will be able to choose from, while the value is what will your server receive (what will enum be resolved to).

The Enum will be registered like any other type in your schema in config/graphq.php:

Then use it like:

Unions

A Union is an abstract type that simply enumerates other Object Types. The value of Union Type is actually a value of one of included Object Types.

It's useful if you need to return unrelated types in the same Query. For example when implementing a search for multiple different entities.

Example for defining a UnionType:

Interfaces

You can use interfaces to abstract a set of fields. Read more about Interfaces here

An implementation of an interface:

A Type that implements an interface:

Supporting custom queries on interface relations

If an interface contains a relation with a custom query, it's required to implement public function types() returning an array of GraphQL::type(), i.e. all the possible types it may resolve to (quite similar as it works for unions) so that it works correctly with SelectFields.

Based on the previous code example, the method would look like:

Sharing interface fields

Since you often have to repeat many of the field definitions of the Interface in the concrete types, it makes sense to share the definitions of the Interface. You can access and reuse specific interface fields with the method getField(string fieldName): FieldDefinition. To get all fields as an array use getFields(): array

With this you could write the fields method of your HumanType class like this:

Or by using the getFields method:

Input Object

Input Object types allow you to create complex inputs. Fields have no args or resolve options and their type must be InputType. You can add rules option if you want to validate input data. Read more about Input Object here

First create an InputObjectType as an extension of the GraphQLType class:

The Input Object will be registered like any other type in your schema in config/graphq.php:

Then use it in a mutation, like:

Type modifiers

Type modifiers can be applied by wrapping your chosen type in Type::nonNull or Type::listOf calls or alternatively you can use the shorthand syntax available via GraphQL::type to build up more complex types.

Field and input alias

It is possible to alias query and mutation arguments as well as input object fields.

It can be especially useful for mutations saving data to the database.

Here you might want the input names to be different from the column names in the database.

Example, where the database columns are first_name and last_name:

JSON columns

When using JSON columns in your database, the field won't be defined as a "relationship", but rather a simple column with nested data. To get a nested object that's not a database relationship, use the is_relation attribute in your Type:

Field deprecation

Sometimes you would want to deprecate a field but still have to maintain backward compatibility until clients completely stop using that field. You can deprecate a field using directive. If you add deprecationReason to field attributes it will become marked as deprecated in GraphQL documentation. You can validate schema on client using Apollo Engine.

Default field resolver

It's possible to override the default field resolver provided by the underlying webonyx/graphql-php library using the config option defaultFieldResolver.

You can define any valid callable (static class method, closure, etc.) for it:

The parameters received are your regular "resolve" function signature.

Macros

If you would like to define some helpers that you can re-use in a variety of your queries, mutations and types, you may use the macro method on the GraphQL facade.

For example, from a service provider's boot method:

The macro function accepts a name as its first argument, and a Closure as its second.

Automatic Persisted Queries support

Automatic Persisted Queries (APQ) improve network performance by sending smaller requests, with zero build-time configuration.

APQ is disabled by default and can be enabled in the config via apq.enabled=true or by setting the environment variable GRAPHQL_APQ_ENABLE=true.

A persisted query is an ID or hash that can be generated on the client sent to the server instead of the entire GraphQL query string. This smaller signature reduces bandwidth utilization and speeds up client loading times. Persisted queries pair especially with GET requests, enabling the browser cache and integration with a CDN.

Behind the scenes, APQ uses Laravel's cache for storing / retrieving the queries. They are parsed by GraphQL before storing, so re-parsing them again is not necessary. Please see the various options there for which cache, prefix, TTL, etc. to use.

Note: it is advised to clear the cache after a deployment to accommodate for changes in your schema!

For more information see:

Note: the APQ protocol requires the hash sent by the client being compared with the computed hash on the server. In case a mutating middleware like TrimStrings is active and the query sent contains leading/trailing whitespaces, these hashes can never match resulting in an error.

In such case either disable the middleware or trim the query on the client before hashing.

Notes

Client example

Below a simple integration example with Vue/Apollo, the createPersistedQueryLink automatically manages the APQ flow.

Misc features

Detecting unused variables

By default, 'variables' provided alongside the GraphQL query which are not consumed, are silently ignored.

If you consider the hypothetical case you have an optional (nullable) argument in your query, and you provide a variable argument for it but you make a typo, this can go unnoticed.

Example:

Variables provided:

In this case, nothing happens and optional_id will be treated as not being provided.

To prevent such scenarios, you can add the UnusedVariablesMiddleware to your execution_middleware.

Configuration options

Guides

Upgrading from v1 to v2

Although version 2 builds on the same code base and does not radically change how the library itself works, many things were improved, sometimes leading to incompatible changes.

Migrating from Folklore

https://github.com/folkloreinc/laravel-graphql, formerly also known as https://github.com/Folkloreatelier/laravel-graphql

Both code bases are very similar and, depending on your level of customization, the migration may be very quick.

Note: this migration is written with version 2.* of this library in mind.

The following is not a bullet-proof list but should serve as a guide. It's not an error if you don't need to perform certain steps.

Make a backup before proceeding!

Performance considerations

Wrap Types

You can wrap types to add more information to the queries and mutations. Similar as the pagination is working you can do the same with your extra data that you want to inject (see test examples). For instance, in your query:

GraphQL testing clients


All versions of graphql-laravel with dependencies

PHP Build Version
Package Version
Requires php Version >= 7.4
ext-json Version *
illuminate/contracts Version ^8.0|^9.0|^10.0
illuminate/support Version ^8.0|^9.0|^10.0
laragraph/utils Version ^1.5
thecodingmachine/safe Version ^1.1|^2.4
webonyx/graphql-php Version ^15
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package convenia/graphql-laravel contains the following files

Loading the files please wait ....