Skip to content

Commit

Permalink
Add @namespaced directive for namespacing by seperation of concerns (
Browse files Browse the repository at this point in the history
…#2478)

Co-authored-by: Will G <[email protected]>
  • Loading branch information
spawnia and sniper7kills authored Dec 6, 2023
1 parent 26eea8b commit 90950d1
Show file tree
Hide file tree
Showing 5 changed files with 230 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ You can find and compare releases at the [GitHub release page](https://github.co

## Unreleased

### Added

- Add `@namespaced` directive for namespacing by separation of concerns https://github.com/nuwave/lighthouse/pull/2469

## v6.24.0

### Added
Expand Down
33 changes: 33 additions & 0 deletions docs/6/api-reference/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -2279,6 +2279,39 @@ extend type Query @namespace(field: "App\\Blog") {

A [@namespace](#namespace) directive defined on a field directive wins in case of a conflict.

## @namespaced

```graphql
"""
Provides a no-op field resolver that allows nesting of queries and mutations.
Useful to implement [namespacing by separation of concerns](https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern).
"""
directive @namespaced on FIELD_DEFINITION
```

The following example shows how one can namespace queries and mutations.

```graphql
type Query {
post: PostQueries! @namespaced
}

type PostQueries {
find(id: ID! @whereKey): Post @find
list(title: String @where(operator: "like")): [Post!]! @paginate
}

type Mutation {
post: PostMutations! @namespaced
}

type PostMutations {
create(input: PostCreateInput! @spread): Post! @create
update(input: PostUpdateInput! @spread): Post! @update
delete(id: ID! @whereKey): Post! @delete
}
```

## @neq

```graphql
Expand Down
33 changes: 33 additions & 0 deletions docs/master/api-reference/directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -2279,6 +2279,39 @@ extend type Query @namespace(field: "App\\Blog") {

A [@namespace](#namespace) directive defined on a field directive wins in case of a conflict.

## @namespaced

```graphql
"""
Provides a no-op field resolver that allows nesting of queries and mutations.
Useful to implement [namespacing by separation of concerns](https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern).
"""
directive @namespaced on FIELD_DEFINITION
```

The following example shows how one can namespace queries and mutations.

```graphql
type Query {
post: PostQueries! @namespaced
}

type PostQueries {
find(id: ID! @whereKey): Post @find
list(title: String @where(operator: "like")): [Post!]! @paginate
}

type Mutation {
post: PostMutations! @namespaced
}

type PostMutations {
create(input: PostCreateInput! @spread): Post! @create
update(input: PostUpdateInput! @spread): Post! @update
delete(id: ID! @whereKey): Post! @delete
}
```

## @neq

```graphql
Expand Down
25 changes: 25 additions & 0 deletions src/Schema/Directives/NamespacedDirective.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php declare(strict_types=1);

namespace Nuwave\Lighthouse\Schema\Directives;

use Nuwave\Lighthouse\Schema\Values\FieldValue;
use Nuwave\Lighthouse\Support\Contracts\FieldResolver;

class NamespacedDirective extends BaseDirective implements FieldResolver
{
public static function definition(): string
{
return /** @lang GraphQL */ <<<'GRAPHQL'
"""
Provides a no-op field resolver that allows nesting of queries and mutations.
Useful to implement [namespacing by separation of concerns](https://www.apollographql.com/docs/technotes/TN0012-namespacing-by-separation-of-concern).
"""
directive @namespaced on FIELD_DEFINITION
GRAPHQL;
}

public function resolveField(FieldValue $fieldValue): callable
{
return static fn (): bool => true;
}
}
135 changes: 135 additions & 0 deletions tests/Integration/Schema/Directives/NamespacedDirectiveTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php declare(strict_types=1);

namespace Tests\Integration\Schema\Directives;

use Tests\DBTestCase;

final class NamespacedDirectiveTest extends DBTestCase
{
public function testCRUDModelDirectives(): void
{
$this->schema .= /** @lang GraphQL */ '
type Query {
user: UserQueries! @namespaced
}
type UserQueries {
find(id: ID! @eq): User @find
list: [User!]! @all
}
type Mutation {
user: UserMutations! @namespaced
}
type UserMutations {
create(name: String!): User @create
update(id: ID!, name: String): User @update
delete(id: ID! @whereKey): User @update
}
type User {
id: ID!
name: String!
}
';

$name = 'foo';
$createUserResponse = $this->graphQL(/** @lang GraphQL */ '
mutation ($name: String!) {
user {
create(name: $name) {
id
name
}
}
}
', [
'name' => $name,
]);
$createUserResponse->assertJson([
'data' => [
'user' => [
'create' => [
'name' => $name,
],
],
],
]);
$userID = $createUserResponse->json('data.user.create.id');

$this->graphQL(/** @lang GraphQL */ '
query ($id: ID!) {
user {
find(id: $id) {
id
}
list {
id
}
}
}
', [
'id' => $userID,
])->assertExactJson([
'data' => [
'user' => [
'find' => [
'id' => $userID,
],
'list' => [
[
'id' => $userID,
],
],
],
],
]);

$newName = 'bar';
$this->graphQL(/** @lang GraphQL */ '
mutation ($id: ID!, $name: String) {
user {
update(id: $id, name: $name) {
id
name
}
}
}
', [
'id' => $userID,
'name' => $newName,
])->assertExactJson([
'data' => [
'user' => [
'update' => [
'id' => $userID,
'name' => $newName,
],
],
],
]);

$this->graphQL(/** @lang GraphQL */ '
mutation ($id: ID!) {
user {
delete(id: $id) {
id
name
}
}
}
', [
'id' => $userID,
])->assertExactJson([
'data' => [
'user' => [
'delete' => [
'id' => $userID,
'name' => $newName,
],
],
],
]);
}
}

0 comments on commit 90950d1

Please sign in to comment.