PHPackages                             scriptle/laragraph - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [API Development](/categories/api)
4. /
5. scriptle/laragraph

ActiveLibrary[API Development](/categories/api)

scriptle/laragraph
==================

graphql-php wrapper for Laravel using PHP8 attributes

0.0.3(5y ago)09MITPHPPHP ^8.0

Since Apr 19Pushed 5y ago1 watchersCompare

[ Source](https://github.com/Akhawais/Laragraph)[ Packagist](https://packagist.org/packages/scriptle/laragraph)[ RSS](/packages/scriptle-laragraph/feed)WikiDiscussions master Synced 4d ago

READMEChangelog (3)Dependencies (1)Versions (4)Used By (0)

LaraGraph
=========

[](#laragraph)

\[WIP\] An elegant wrapper to `webonyx/graphql-php` that uses PHP 8 attributes.

Installation
============

[](#installation)

> Requirements: PHP 8

`composer require scriptle/laragraph`

Usage
=====

[](#usage)

Publish the config file:

`php artisan vendor:publish --provider=Scriptle\\Laragraph\\LaragraphServiceProvider`

Amend the schemas to your preference.

Folder Structure
----------------

[](#folder-structure)

- Mutation roots live in `app/GraphQL/Mutations`
- Query roots live in `app/GraphQL/Queries`
- Types live in `app/GraphQL/Types`

`app/Models` is also traversed for models with GraphQL `Type` attributes present.

Schema
------

[](#schema)

Schemas are defined in `config/laragraph.php` under the `schemas` key.

```
return [
    'prefix' => 'gql',
    'schemas' => [
        'v1' => [
            'schema' => [
                'query' => 'V1Query',
                'mutation' => 'V1Mutation',
            ],
            'middleware' => null,
        ],
        /* 'v2' => [
        *       'schema' => [
        *           'query' => 'V2Query',
        *           'mutation' => 'V2Mutation',
        *       ],
        *       'middleware' => 'throttle:60,1',
        *   ]
        */
    ]
];
```

The prefix (`gql`) is prepended to all schemas. The schema key is the URL. So for `v1`, the full URL is `/gql/v1`.

Within the `schema` key you define your GraphQL schema as usual, referencing the root types by string.

You can add custom `middleware` with that key, such as an entire schema limited to admin users.

Then, you must add your root types as you defined them, like so:

```
namespace App\GraphQL\Queries;
use Scriptle\Laragraph\Type;
use App\Models\User;
...
#[Type('V1Query', 'Root queries for v1')]
class V1Query {
    #[Field('users', '[User]!', 'Lists all users.')]
    public function users() {
        return User::all();
    }

    // More on this later
    #[Field('lookupUser("User ID" id: String, "User Email" email: String)', 'User', 'Look up a user by ID or email.')]
    public function lookupUser($args) {
        // More on this later
        return User::where($args)->first();
    }
}
```

Attributes
----------

[](#attributes)

On the **class**, add the following attribute:

```
namespace App\Models\User;
use Scriptle\Laragraph\Type;
...
#[Type]
class User extends Authenticatable {
    ...
}
```

`#[Type]` on its own will use the class name as the GraphQL type name.

`#[Type('Person')]` will use `Person` as the GraphQL type name.

`#[Type('User', 'A user in the database.')]` will use `User` as the GraphQL type name, plus a GraphQL introspection descriptor for this type.

### Defining Fields

[](#defining-fields)

To define simple fields returned through Eloquent, you can simply attach them with the `Type` attribute:

```
namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
}
```

Note: Eloquent relationships are automatically supported this way.

### Fields with a custom resolver

[](#fields-with-a-custom-resolver)

If your field is not database-based, or needs to be passed through a callback you can use this feature.

EITHER:

```
namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    public function resolveLastNameField()
    {
        return strtoupper($this->attributes['last_name']);
    }
}
```

Format: `resolve` + (StudlyCase) `LastName` + `Field` = `resolveLastNameField`

OR

```
namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
use Scriptle\Laragraph\ResolvesFor;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('last_name', 'String!', "User's last name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    #[ResolvesFor('last_name')]
    public function getLastNameAttribute()
    {
        return strtoupper($this->attributes['last_name']);
    }
}
```

Function can be named anything as long as it has the `ResolvesFor` attribute. This hooks in nicely with Laravel's custom getters.

OR LASTLY:

```
namespace App\Models\User;
use Scriptle\Laragraph\Type;
use Scriptle\Laragraph\Field;
...
#[
    Type('User', 'A user in the database.'),
    Field('id', 'String!', 'User ID'),
    Field('first_name', 'String!', "User's first name"),
    Field('roles', '[Role]!', 'Array of user roles'),
]
class User extends Authenticatable {
    ...
    #[Field('last_name', 'String!', "User's last name")]
    public function anything()
    {
        return strtoupper($this->attributes['last_name']);
    }
}
```

Move the Field attribute down to the function instead, if you prefer this style.

### Argument-ed Fields

[](#argument-ed-fields)

Some fields, especially in queries, need arguments. The syntax is direct GraphQL definition syntax:

`#[Field('lookupUser("User ID" id: String!)', 'User', 'Look up a user by ID.')]`

This defines a `lookupUser` field with 1 argument, `id` of type `String!` (with ! so it must be non-null) and with introspection description of `User ID`.

The same can be done for mutations or querying fields on types.

Custom Types
------------

[](#custom-types)

Custom Types can be defined like the User model above, and can be placed in the `app/GraphQL/Types` folder to keep them separate from your models. This is useful for mutation responses, or other complex response structures.

Types are referenced by their type name (as registered by the `#[Type]` attribute), just with regular GraphQL. **There is no need to create a variable or reference classes directly!**

Caching
=======

[](#caching)

The `config/laragraph.php` will be cached along with Laravel's regular config caching (`php artisan config:cache` || `php artisan config:clear`)

You can also cache Laragraph's Type mappings to avoid processing these on each request. Use `php artisan gql:cache` to cache, and `php artisan gql:clear` to remove.

###  Health Score

22

—

LowBetter than 22% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

1853d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1143425?v=4)[Dylan Akhawais](/maintainers/akhawais)[@Akhawais](https://github.com/Akhawais)

---

Top Contributors

[![Akhawais](https://avatars.githubusercontent.com/u/1143425?v=4)](https://github.com/Akhawais "Akhawais (11 commits)")

### Embed Badge

![Health badge](/badges/scriptle-laragraph/health.svg)

```
[![Health](https://phpackages.com/badges/scriptle-laragraph/health.svg)](https://phpackages.com/packages/scriptle-laragraph)
```

###  Alternatives

[nuwave/lighthouse

A framework for serving GraphQL from Laravel

3.5k10.7M93](/packages/nuwave-lighthouse)[thecodingmachine/graphqlite

Write your GraphQL queries in simple to write controllers (using webonyx/graphql-php).

5723.1M30](/packages/thecodingmachine-graphqlite)[wp-graphql/wp-graphql

GraphQL API for WordPress

3.8k391.7k19](/packages/wp-graphql-wp-graphql)[overblog/graphql-bundle

This bundle provides tools to build a GraphQL server in your Symfony App.

8027.9M28](/packages/overblog-graphql-bundle)[wheelpros/fitment-platform-api

Magento 2 (Open Source)

12.1k1.2k](/packages/wheelpros-fitment-platform-api)[aimeos/ai-admin-graphql

Aimeos Admin GraphQL API extension

944100.0k4](/packages/aimeos-ai-admin-graphql)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
