lighthouse icon indicating copy to clipboard operation
lighthouse copied to clipboard

Support multiple schemas

Open yaquawa opened this issue 7 years ago • 39 comments

I have a situation where I need multiple GraphQL endpoints for various access controls.

For example, there could be a public endpoint for creating user account, a private endpoint protected by auth middleware, or a private endpoint for super-admin accounts also protected by auth:admin middleware.

It makes sense that each of these roles should have their own GraphQL schema but not a "god schema" that covers all.

Currently, I can achieve this by getting rid of the middleware in config/lighthouse.php and set middleware for each field using the @middleware directive directly. But I'm wondering if this is the best practice for designing a nice GraphQL schema?

Anyway, I think there are some use cases for having multiple schemas. How do you think?

Solution

The value of config/lighthouse.php could be an array in an array, which each element of the root array represents a schema setting.

return [
    [
        'route_name' => 'graphql',

        'route_enable_get' => true,

        'route'           => [
            'prefix'     => '',
            'middleware' => ['api'],
        ],
    ],
    [
        'route_name' => 'public-graphql',

        'route_enable_get' => false,

        'route'           => [
            'prefix'     => '',
            'middleware' => ['public-api'],
        ],
    ],
];

yaquawa avatar Aug 20 '18 00:08 yaquawa

For your specific use-case, the @group directive should suffice as a convenient way to apply common middleware to multiple fields. Check out the PR i just made to the docs repo https://github.com/nuwave/lighthouse/issues/273 . I think this should solve your issue.

However, i am leaving this issue open for the moment as a place for discussion around multi-schema.

In general the philosophy of GraphQL goes against it, the tendency is actually to stitch-together schemas from multiple sources all into one. Also, the config change you proposed is only a small piece of the puzzle. Behind the scenes, multi-schema will require major changes as well as lots of additional complexity. I would hold off on it unless a use-case comes along which truly can not be dealt with in another way.

spawnia avatar Aug 20 '18 06:08 spawnia

@spawnia Thanks!! I found the @group directive as you mentioned in the docs https://lighthouse-php.netlify.com/docs/directives-security.html#group

where it's using the @middleware

# the "auth:api" middleware will be run on all fields
type Query @middleware(checks: ["auth:api"]) {
  users: [User]
  posts: [Post]
}

does this is a typo…?

yaquawa avatar Aug 20 '18 18:08 yaquawa

Yup https://github.com/nuwave/lighthouse-docs/pull/33 it is a typo. I recommend to use the next branch of the docs

spawnia avatar Aug 20 '18 18:08 spawnia

@spawnia Okay, Thank you!

yaquawa avatar Aug 20 '18 21:08 yaquawa

Closing this for now, if some more interest in this pops up we might discuss it again. You might not need it as you can just:

  • Use @can or @middleware to restrict access to parts of the schema
  • Split your app across microservices

spawnia avatar Sep 03 '18 20:09 spawnia

@spawnia In my case, I have a service for both global and internal access. And I want to provide GraphQL API for both of them, and most importantly, I don't want to expose my schema for internal usage to global. It's not based on different users, It's a service that is serving both the users or third parties and other services on my cloud.

yz89122 avatar Jun 07 '20 08:06 yz89122

I tried to solve through provider overrides, but in this option, when the cache is turned on, the scheme is not visible, here is an example: 1 - config/lighthouse.php

'schema' => [
        'register' => base_path('graphql/schema.graphql'),
        'api_admin' => base_path('graphql/admin/api_admin.graphql'),
        'api_front' => base_path('graphql/front/api_front.graphql'),
],

2 - create provider SchemaLighthouseServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider;
use Nuwave\Lighthouse\Schema\Source\SchemaStitcher;

class SchemaLighthouseServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot(): void
    {
        //
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register(): void
    {
        $this->app->singleton( SchemaSourceProvider::class, function (): SchemaStitcher {

            if( isset( $_GET['key'] ) && $_GET['key'] ) == 'adminpanel'  ){

                return new SchemaStitcher(
                    config( 'lighthouse.schema.api_admin', '' )
                );

            } else {

                return new SchemaStitcher(
                    config( 'lighthouse.schema.api_front', '' )
                );

            }

        });
    }

}

3 - add provider in config/app.php

'providers' => [
       // ...
      App\Providers\SchemaLighthouseServiceProvider::class,
],

4 - open graphql-playground exemple admin panel: mydomain.local/graphql?key=adminpanel work schema: api_admin.graphql

exemple front site: mydomain.local/graphql work schema api_front.graphql

!!!But this does not work when cache is enabled

'cache' => [
        'enable' => env('LIGHTHOUSE_CACHE_ENABLE', true),
],

If anyone has ideas and solutions, write

as-yakovenko avatar Jun 10 '20 08:06 as-yakovenko

The main point that is unclear to me is which parts of the configuration should be global and which ones have to be schema-specific.

Obviously the schema path has to change, but what about route, guard, cache and others?

Choosing between schema's seems simple enough, we could add an interface like this:

interface SelectsSchema {
    public function configKey(): string // e.g. admin, public
}

Or possibly something even more dynamic that can just return a partial config array.

spawnia avatar Jun 10 '20 11:06 spawnia

the task is the same as that of @yanzhen0610 , to make separate scheme. The visibility of mutation and query was different depending on the request admin or public. Thanks for the answer, today I will try the option through the interface.

as-yakovenko avatar Jun 10 '20 11:06 as-yakovenko

To be clear: Lighthouse has no such mechanism as of now. I propose that we might add something like this in a future PR.

spawnia avatar Jun 10 '20 12:06 spawnia

This would be a great solution to limit the visibility of mutation and query.

exemple: scheme - api_admin.graphql / uri - mydomain.local/admin-graphql
- only mutations and requests related to admin panel settings are visible
exemple: scheme - api_front.graphql / uri - mydomain.local/graphql
- all mutations and query related to user functionality are visible
exemple: scheme - api_order.graphql / uri - mydomain.local/orders-graphql
- by analogy as in Rest Api, receiving only orders per day

or maybe some other option, as I described above, give get parameter

as-yakovenko avatar Jun 10 '20 13:06 as-yakovenko

in my example above, I made it possible to see different schemes, but then you need to turn off the cache

as-yakovenko avatar Jun 10 '20 13:06 as-yakovenko

Thank you to the contributors for providing such an amazing library.

It would be great to expose the option to configure schemas from multiple entry points, for example, if packages are aware of the lighthouse package being installed they could expose their own individual schema as well under their own namespace.

lukesiedle avatar Jun 26 '20 14:06 lukesiedle

Also would like have a internal and public facing schema, each with their own methods of authentication.

The solution today would be to either name these a certain naming convention but the schema would be visible in both endpoints or to spin up two instances and find a way to reuse the code between projects right?

gjreasoner avatar Jun 26 '20 15:06 gjreasoner

I have the exact same use case as @luke-siedle mentioned, plus my package has multiple schema endpoints (one that is dynamically generated, and one that uses .graphql schemas).

I ended up copying most of the Lighthouse repository into my own, which is totally unacceptable in terms of maintainability (and this is not even our core business), but it's what is going to solve it for me right now since I'm mostly interested in the way Lighthouse extends webonyx/graphql-php and make it easier to use.

Through reading and understanding how Lighthouse works, I found that:

  • There are direct calls to app() and config() around the repository
  • The service container has several Singleton classes
  • The schema parsing and document generation are bound to each other
  • Lighthouse automatically exposes its ServiceProvider on composer.json

What I did to get this roughly working, mostly workarounds right now:

  • Created my own LighthouseContainer extending from Illuminate\Container\Container
  • Bound this new container to Laravel's through a callback (so I can fetch new instances)
    • Bound all the Lighthouse's service providers within LighthouseContainer
      • I kept singletons as singletons since they now live within the scope of LighthouseContainer instance
  • Changed all calls to app() to $this->container->make in which container is a LighthouseContainerinstance
  • Changed all calls to config() to an injected instance of Illuminate\Config\Repository
  • DocumentAST is a singleton resolving to null by default.
  • Schema is a singleton resolving to null by default.

Now for every instance of LighthouseContainer, I can ask for an instance of Lighthouse\GraphQL , and given that Lighthouse\GraphQL is the root class for all the following injections, whenever you make a new instance of it, you get a fully independent GraphQL instance.

To get an instance of DocumentAST and Shema, I do a $container->extend() and I load the contents the way I want in there, returning the proper instance.

My two cents

Lighthouse provides a hell lot of cool features over webonyx/graphql-php like directives that can mutate almost anything you want, middlewares, and the most painful one IMHO which is resolvers (this is why I'm heavily dependent on Lighthouse's repository right now).

It would be really nice if Lighthouse had it's own core package that contains those features and allows it to be used separately from Lighthouse itself, while supporting instantiating multiple instances of it. Right now, it doesn't seem suitable for usage in other packages and/or projects that needs multiple different endpoints.

The main Lighthouse should be able to work just the way it works right now, but instead of containing all the code it just instantiates services from the Core package.

I'm willing to give it a try as soon as I get an alpha going for the project I'm working on right now, since I'm expecting it to become unmaintainable in the long run for us.

@spawnia let me know if it makes sense and/or if you are interested in discussing something like this

WoLfulus avatar Aug 01 '20 17:08 WoLfulus

@WoLfulus Interesting stuff!

So far, the focus for Lighthouse has mostly been ease of use. There are some architectural decisions that were made so that it requires as little config as possible, enables writing elegant code and it just works™.

That said, I would not mind modularizing the core code a bit more, as long as we are still able to wrap it up nicely into an easy package. If that can be done without breaking changes for library users - great!

If not, an architectural overhaul could be the next big thing for a future v6. We are in the process of working towards v5 now, which is mostly a cleanup of many quirky features the library has grown over time, switching to sane defaults, removing some workarounds, ...

spawnia avatar Aug 03 '20 07:08 spawnia

That would be awesome! We can leverage most of Lighthouse's features on our CMS.

This should make it really easy to work with resolvers and building an executable schema - having a way to use it decoupled from Lighthouse would be awesome. I'm struggling quite a bit (for a while now) to get things to work since I'm not that familiar with GraphQL implementations and it's been really confusing to properly do things directly into webonyx (btw, the whole middleware and directive based approach in Lighthouse is awesome for that matter).

Let me know how we can get in touch so we can talk more about it (If you're on Discord, my tag is WoLfulus#1560). I'd love some inputs and how to move forward with an implementation even if it's totally separate from Lighthouse itself, since touching it would bring huge architectural changes as you mentioned.

Thanks!

WoLfulus avatar Aug 03 '20 08:08 WoLfulus

@WoLfulus we can extract useful components and launch them as separate projects under https://github.com/laragraph

You can join our Slack https://join.slack.com/t/lighthouse-php/shared_invite/enQtMzc1NzQwNTUxMjk3LWMyZWRiNWFmZGUxZmRlNDJkMTQ2ZDA1NzQ1YjVkNTdmNWE1OTUyZjZiN2I2ZGQxNTNiZTZiY2JlNmY2MGUyNTQ

spawnia avatar Aug 03 '20 11:08 spawnia

Another user case for multiple schemas.

I have several separate products developed in VUE. Each has a separate Node server with GraphQL. The aim is that all products talk GraphQL with one Laravel server. Each product get its own Laravel package with its own schema and its own end point. If a product need its own server then I will uninstall that package and install it on a new Laravel server.

The options I have today is to offer one product to run GraphQL and the rest will have to switch to REST. Or spin up several Laravel servers, one for each product like we have today with Node.

peterlembke avatar Oct 21 '20 14:10 peterlembke

Just a few ideas to overcome the multple endpoint issue:

If you need multiple endpoints, create multiple projects. Models can come from various locations, so you can place your models in a private package.

@peterlembke, could you do something with the subdomain? that way you can point the default schema to a file that has common functionality, and the rest can be outputted using the BuildSchemaString event based on the url. The cache key is configurable so you can use the domainname there as well. https://lighthouse-php.com/master/digging-deeper/adding-types-programmatically.html#additional-schema-definitions

henzeb avatar Nov 18 '20 14:11 henzeb

More than one year later I reopen the subject !

For a personal project I build a "custom way" to manage several GraphQL endpoints, what do you think about my approach ?

Notion article of my approach

Would it be possible/interesting to do some PR based on this logic ? I share this message on slack too !

Ashk2a avatar Nov 27 '21 10:11 Ashk2a

More than one year later I reopen the subject !

For a personal project I build a "custom way" to manage several GraphQL endpoints, what do you think about my approach ?

Notion article of my approach

Would it be possible/interesting to do some PR based on this logic ? I share this message on slack too !

I got this error Call to undefined method Nuwave\Lighthouse\Schema\Source\SchemaStitcher::setRootPath()

kieuminhcanh avatar Mar 26 '22 19:03 kieuminhcanh

i think 1 of the workaround for this is to hide some queries/mutations from schema unless a specific API key is present, custom directive will able to achieve this, the only problem is the schema caching

eslym avatar Aug 09 '22 07:08 eslym

More than one year later I reopen the subject !

For a personal project I build a "custom way" to manage several GraphQL endpoints, what do you think about my approach ?

Notion article of my approach

Would it be possible/interesting to do some PR based on this logic ? I share this message on slack too !

If I try Subscription receive the next error:

Error: Typed property App\GraphQL\Schema\Source\DynamicSchemaSourceProvider::$rootSchemaPath must not be accessed before initialization in file /var/www/html/app/GraphQL/Schema/Source/DynamicSchemaSourceProvider.php on line 43

EugeneMeles avatar Aug 19 '22 12:08 EugeneMeles

This method can hide fields from schema when needed

type Query {
    "This orders will not shown when there is no admin parameter in the url search param"
    orders: [Order!]! @hideWhen(predicate: "App\\GraphQL\\Predicates\\NotAdmin")
}
<?php
namespace App\GraphQL\Directives;

use GraphQL\Language\AST\FieldDefinitionNode;
use GraphQL\Language\AST\ObjectTypeDefinitionNode;
use Nuwave\Lighthouse\Schema\AST\DocumentAST;
use Nuwave\Lighthouse\Schema\Directives\BaseDirective;
use Nuwave\Lighthouse\Support\Contracts\FieldManipulator;

final class HideWhenDirective extends BaseDirective implements FieldManipulator
{
    public static function definition(): string
    {
        return /** @lang GraphQL */ <<<'GRAPHQL'
directive @hideWhen(predicate: String!) on FIELD_DEFINITION
GRAPHQL;
    }

    /**
     * Manipulate the AST based on a field definition.
     *
     * @param DocumentAST $documentAST
     * @param FieldDefinitionNode $fieldDefinition
     * @param ObjectTypeDefinitionNode $parentType
     * @return void
     */
    public function manipulateFieldDefinition(
        DocumentAST              &$documentAST,
        FieldDefinitionNode      &$fieldDefinition,
        ObjectTypeDefinitionNode &$parentType
    ): void
    {
        $predicate = $this->directiveArgValue('predicate');
        if (class_exists($predicate)) {
            $predicate = new $predicate;
        }
        if (call_user_func($predicate)) {
            foreach ($parentType->fields as $index => $field) {
                if ($field === $fieldDefinition) {
                    $parentType->fields->offsetUnset($index);
                    break;
                }
            }
        }
    }
}
<?php
namespace App\GraphQL\Predicates;

class NotAdmin
{
    public function __invoke(): bool
    {
        return !request()->query->has('admin');
    }
}

but this method can only work without schema cache enabled, the manipulation will not go through again after cache

Updates i managed to make this method work while still can cache most of the schema generation https://gist.github.com/eslym/658ab5eb9b481e7615234993263b1a10

eslym avatar Oct 27 '22 03:10 eslym

Almost perfect solution differentiate multiple schema by query parameter

  1. Add a service provider alter config before resolving ASTBuilder and ASTCache
app/Providers/MultiLighthouseServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Http\Request;
use Illuminate\Support\ServiceProvider;
use Nuwave\Lighthouse\Schema\AST\ASTCache;
use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider;

class MultiLighthouseServiceProvider extends ServiceProvider
{
    protected $schemaResolved = false;
    protected $cacheResolved = false;

    public function register()
    {
        $this->app->beforeResolving(SchemaSourceProvider::class, function () {
            if ($this->schemaResolved) return;
            [$schema, $path] = $this->locateEntry();
            if (!$schema) {
                return; // no entry defined
            }
            config()->set('lighthouse.schema.register', $path);
            $this->schemaResolved = true;
        });
        $this->app->beforeResolving(ASTCache::class, function () {
            if ($this->cacheResolved) return;
            [$schema] = $this->locateEntry();
            if (!$schema) {
                return;
            }
            static::patchCacheConfig($schema);
            $this->cacheResolved = true;
        });
    }

    protected function locateEntry(): array
    {
        /** @var Request $request */
        $request = $this->app->make('request');
        $schema = $request->query->get('schema');
        $entries = config('lighthouse.schema.entries', []);
        if (!key_exists($schema, $entries)) {
            return [null, null];
        }
        return [$schema, $entries[$schema]];
    }

    public static function patchCacheConfig($schema)
    {
        $cacheKey = config('lighthouse.cache.key');
        $cachePath = config('lighthouse.cache.path');
        config()->set('lighthouse.cache.key', "$cacheKey-$schema");

        // the final filename won't look good but its cache file anyway ¯\_(ツ)_/¯
        config()->set('lighthouse.cache.path', "$cachePath-$schema.php");
    }
}
  1. Add a command to override the original cache
app/Console/Commands/LighthouseCacheCommand.php
<?php

namespace App\Console\Commands;

use App\Providers\MultiLighthouseServiceProvider;
use Illuminate\Contracts\Events\Dispatcher;
use Nuwave\Lighthouse\Console\CacheCommand;
use Nuwave\Lighthouse\Schema\AST\ASTBuilder;
use Nuwave\Lighthouse\Schema\AST\ASTCache;
use Nuwave\Lighthouse\Schema\DirectiveLocator;
use Nuwave\Lighthouse\Schema\Source\SchemaSourceProvider;
use Nuwave\Lighthouse\Schema\Source\SchemaStitcher;

class LighthouseCacheCommand extends CacheCommand
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'lighthouse:cache';

    public function handle(ASTBuilder $builder, ASTCache $cache): void
    {
        parent::handle($builder, $cache);

        $entries = config('lighthouse.schema.entries');
        
        $cacheKey = config('lighthouse.cache.key');
        $cachePath = config('lighthouse.cache.path');
        foreach ($entries as $schema => $path) {
            MultiLighthouseServiceProvider::patchCacheConfig($schema);
            $builder = new ASTBuilder(
                app(DirectiveLocator::class),
                $source = new SchemaStitcher($path),
                app(Dispatcher::class),
                $cache = new ASTCache(config())
            );
            // Rebound classes
            app()->singleton(SchemaSourceProvider::class, fn() => $source);
            app()->singleton(ASTBuilder::class, fn() => $builder);
            app()->singleton(ASTCache::class, fn() => $cache);
            parent::handle($builder, $cache);
            
            // restore config for next loop
            config()->set('lighthouse.cache.key', $cacheKey);
            config()->set('lighthouse.cache.path', $cachePath);
        }
    }
}

  1. Add the service provider to config/app.php
<?php
return [
    //...
    'providers' => [
    //...
        App\Providers\MultiLighthouseServiceProvider::class, // <= add this line
    //...
    ]
];
  1. Add your schema to config/lighthouse.php
<?php
return [
    //...
    'schema' => [
        'register' => base_path('graphql/schema.graphql'), // <= this schema will use as default schema

        'entries' => [
            'admin' => base_path('graphql/admin.graphql') // <= add any extra schemas here
        ]
    ],
    //....
];

after all these modification, now /graphql?schema=admin will resolved to graphql/admin.graphql while /graphql will still resolved to the default graphql/schema.graphql, and cache works fine, php artisan lighthouse:cache will now cache all schema

Any downside? well, obviously things like Laravel Octane will break this mechanism ╮(╯_╰)╭ but usual php hosting should be fine with this method

eslym avatar Oct 28 '22 08:10 eslym

I commented on this 2 years ago. We immediately created a schema stitching and a system for multiple endpoints.

It is not a public package. Is there an interest for that?

We can have one schema and one config and one endpoint for each Laravel package. In each package lighthouse.php config file we have added config what schemas this specific application want.

    /*
    |--------------------------------------------------------------------------
    | Stitch of packages
    |--------------------------------------------------------------------------
    |
    | Add the package names in an array.
    | Remember to add your own package name here as well.
    |
    | Example of package names "laravel_actionplan", "laravel_division"
    |
    */

    'stitch' => [
        'laravel_graphql',
        'laravel_self_survey',
        'laravel_actionplan',
        'laravel_user',
        'laravel_right',
        "laravel_$nameLower" <-- See below
    ],

We have a generic config file and have $name = 'Analytics'; $nameLower = 'analytics'; at the top. We can then copy the config file to a new package and just change at the top.

The stitching create one schema for each laravel package that use GraphQL. They are placed in root/graphql/package_name/

An artisan command stitch named schemas or all of them.

 graphql
  graphql:stitch                       Stitch together multiple graphql schemas
  graphql:stitch:all                   Stitch all schemas in all packages

The stitch all:

Stitching complete for package: actionplan
Stitching complete for package: analytics
Stitching complete for package: atlas
Stitching complete for package: customer
Stitching complete for package: division
Stitching complete for package: dynamic_benchmark
Stitching complete for package: file
Stitching complete for package: graphql
Stitching complete for package: license
Stitching complete for package: media
Stitching complete for package: project
Stitching complete for package: question
Stitching complete for package: right
Stitching complete for package: self_survey
Stitching complete for package: send
Stitching complete for package: survey
Stitching complete for package: user
Stitching complete for package: user_message

When lighthouse load the schema then we have overridden that code and check what controller is requesting the schema. We pick the right schema and right config file. Lighthouse also compile the schema lighthouse-schema.php without problems.

Setting up a controller in each package is easy. We extend a parent controller and just set some constants.

namespace MyDomain\MyPackage\Controller;
use OurPackage\GraphQL\Controller\GraphQLController as ParentGraphQLController;
class GraphQLController extends ParentGraphQLController
{
    const CONFIG_PATH = 'graphql/my_package/lighthouse.php';
    const CONFIG_PATH_PACKAGE_NAME = 'vendor/my_domain/laravel_%s/src/GraphQL/Config/lighthouse.php';
    const SCHEMA_PATH = 'graphql/my_package/schema.graphql';
    const SCHEMA_PATH_PACKAGE_NAME = 'vendor/my_domain/laravel_%s/src/GraphQL/Schema/schema.graphql';
    const SCHEMA_NAME = 'My package schema';
}

The schema are displayed if we get a GET to the endpoint instead of a POST.

Issues we had with this setup is changes in the lighthouse package. We have had to change the override twice when there are changes in Lighthouse. But mostly there is no problem upgrading to the latest Lighthouse. For new versions of Lighthouse we also need to compare each of our lighthouse.php config files with the original in Lighthouse so that we have all the latest settings.

This have worked well for us for two years on our live sites.

Lighthouse is excellent. ❤️

peterlembke avatar Nov 16 '22 07:11 peterlembke

I commented on this 2 years ago. We immediately created a schema stitching and a system for multiple endpoints.

It is not a public package. Is there an interest for that?

We can have one schema and one config and one endpoint for each Laravel package. In each package lighthouse.php config file we have added config what schemas this specific application want.

    /*
    |--------------------------------------------------------------------------
    | Stitch of packages
    |--------------------------------------------------------------------------
    |
    | Add the package names in an array.
    | Remember to add your own package name here as well.
    |
    | Example of package names "laravel_actionplan", "laravel_division"
    |
    */

    'stitch' => [
        'laravel_graphql',
        'laravel_self_survey',
        'laravel_actionplan',
        'laravel_user',
        'laravel_right',
        "laravel_$nameLower" <-- See below
    ],

We have a generic config file and have $name = 'Analytics'; $nameLower = 'analytics'; at the top. We can then copy the config file to a new package and just change at the top.

The stitching create one schema for each laravel package that use GraphQL. They are placed in root/graphql/package_name/

An artisan command stitch named schemas or all of them.

 graphql
  graphql:stitch                       Stitch together multiple graphql schemas
  graphql:stitch:all                   Stitch all schemas in all packages

The stitch all:

Stitching complete for package: actionplan
Stitching complete for package: analytics
Stitching complete for package: atlas
Stitching complete for package: customer
Stitching complete for package: division
Stitching complete for package: dynamic_benchmark
Stitching complete for package: file
Stitching complete for package: graphql
Stitching complete for package: license
Stitching complete for package: media
Stitching complete for package: project
Stitching complete for package: question
Stitching complete for package: right
Stitching complete for package: self_survey
Stitching complete for package: send
Stitching complete for package: survey
Stitching complete for package: user
Stitching complete for package: user_message

When lighthouse load the schema then we have overridden that code and check what controller is requesting the schema. We pick the right schema and right config file. Lighthouse also compile the schema lighthouse-schema.php without problems.

Setting up a controller in each package is easy. We extend a parent controller and just set some constants.

namespace MyDomain\MyPackage\Controller;
use OurPackage\GraphQL\Controller\GraphQLController as ParentGraphQLController;
class GraphQLController extends ParentGraphQLController
{
    const CONFIG_PATH = 'graphql/my_package/lighthouse.php';
    const CONFIG_PATH_PACKAGE_NAME = 'vendor/my_domain/laravel_%s/src/GraphQL/Config/lighthouse.php';
    const SCHEMA_PATH = 'graphql/my_package/schema.graphql';
    const SCHEMA_PATH_PACKAGE_NAME = 'vendor/my_domain/laravel_%s/src/GraphQL/Schema/schema.graphql';
    const SCHEMA_NAME = 'My package schema';
}

The schema are displayed if we get a GET to the endpoint instead of a POST.

Issues we had with this setup is changes in the lighthouse package. We have had to change the override twice when there are changes in Lighthouse. But mostly there is no problem upgrading to the latest Lighthouse. For new versions of Lighthouse we also need to compare each of our lighthouse.php config files with the original in Lighthouse so that we have all the latest settings.

This have worked well for us for two years on our live sites.

Lighthouse is excellent. ❤️

Is your stitching based on this? https://lighthouse-php.com/5/digging-deeper/adding-types-programmatically.html

Stevemoretz avatar Mar 12 '23 21:03 Stevemoretz

I hope this function can be integrated into the core and receive official support.

kieuminhcanh avatar Mar 22 '23 23:03 kieuminhcanh

I would like a multiple schema if it's possible. It's in order to make easier control what to share in the public schema. For instance

type Post {
  id
  name
  private_filed_1
  private_filed_2
  private_filed_3
  private_filed_4
}

I know I can add the directive in each private field. But if you have many models with many private fields, it's easier to have a public/private schema instead to add the directive in each field. Also, it's faster, because my code doesn't have to review each right in each column in every request.

Or if there is a way to create other type that I can attach to the Post model? like:

type PostPublic {
  id
  name
}

albertcito avatar Aug 16 '23 18:08 albertcito