Skip to content

Commit

Permalink
Create documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
jerowork committed Jan 3, 2025
1 parent 8c143a7 commit 4795c90
Show file tree
Hide file tree
Showing 5 changed files with 549 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# GraphQL Attribute Schema
Build your GraphQL Schema (for [webonyx/graphql-php](https://github.com/webonyx/graphql-php)) based on attributes.

**Note:** this library is still work in progress, and misses some valuable features (see [todo](docs/todo.md))

## Why this library?
[webonyx/graphql-php](https://github.com/webonyx/graphql-php) requires a `Schema` in order to create a GraphQL Server.
This schema configuration is based on (large) PHP arrays.

Wouldn't it be nice to have a library in between which can read your mutation, query and type classes instead, and create
that schema configuration for you?

This is where *GraphQL Attribute Schema* comes into place. By adding attributes to your classes,
*GraphQL Attribute Schema* will create the schema configuration for you.

## Documentation
Documentation is available in the [docs](docs/index.md) directory.
99 changes: 99 additions & 0 deletions docs/getting_started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Getting started

## Requirements
*GraphQL Attribute Schema* is a standalone library. However, it needs a couple of other libraries to work:

- The main GraphQL library [webonyx/graphql-php](https://github.com/webonyx/graphql-php)
- A [psr/container](https://github.com/php-fig/container) compatible container (PSR-11), e.g.:
- [php-di/php-di](https://github.com/PHP-DI/PHP-DI)
- [symfony/dependency-injection](https://github.com/symfony/dependency-injection), by default included in the Symfony framework

## Installation
Install via composer:
```bash
composer require jerowork/graphql-attribute-schema
```

## Integration with webonyx/graphql-php
In order to create a `Schema` for webonyx/graphql-php, a `SchemaBuilder` is provided in this library.
This `SchemaBuilder` requires an 'Abstract Syntax Tree' (or AST), which can be created with the `Parser`.

Both `SchemaBuilder` and `Parser` can be created quickly with the provided factories:

```php
use GraphQL\Server\StandardServer;
use GraphQL\Server\ServerConfig;
use Jerowork\GraphqlAttributeSchema\Parser\ParserFactory;
use Jerowork\GraphqlAttributeSchema\SchemaBuilderFactory;

// PSR-11 compatible container of your choice
$container = new YourPsr11Container();

// 1. Create an AST based on your classes
$ast = ParserFactory::create()->parse(__DIR__ . '/Path/To/GraphQL');

// 2. Create the schema configuration
$schema = SchemaBuilderFactory::create($container)->build($ast);

// 3. Add schema to e.g. webonyx StandardServer
$server = new StandardServer(ServerConfig::create([
'schema' => $schema,
]));
```

*GraphQL Attribute Schema* does not create a GraphQL Server for you.
How to create a GraphQL Server, please check e.g. https://webonyx.github.io/graphql-php/executing-queries/#using-server

### Example GraphQL Server with Symfony

As a quick-start, a simple example of a GraphQL Server with Symfony
(requiring [symfony/psr-http-message-bridge](https://github.com/symfony/psr-http-message-bridge) and a PSR-7 implementation, e.g. [guzzlehttp/psr7](https://github.com/guzzle/psr7)):

_Note: any error handling is absent to keep the example simple._
```php
use GraphQL\Server\StandardServer;
use GraphQL\Server\ServerConfig;
use Jerowork\GraphqlAttributeSchema\Parser\ParserFactory;
use Jerowork\GraphqlAttributeSchema\SchemaBuilderFactory;
use Psr\Container\ContainerInterface;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Attribute\AsController;
use Symfony\Component\Routing\Attribute\Route;

#[AsController]
final readonly class GraphQLServerController
{
public function __construct(
private ContainerInterface $container,
private HttpMessageFactoryInterface $httpMessageFactory,
) {}

#[Route('/graphql', name: 'graphql.server', methods: Request::METHOD_POST)]
public function __invoke(Request $request): Response
{
$ast = ParserFactory::create()->parse(__DIR__ . '/Path/To/GraphQL');
$schema = SchemaBuilderFactory::create($container)->build($ast);

$server = new StandardServer(ServerConfig::create([
'schema' => $schema,
]));

$result = $server->executePsrRequest(
$this->httpMessageFactory
->createRequest($request)
->withParsedBody(json_decode($request->getContent(), true, flags: JSON_THROW_ON_ERROR)),
);

// Batch requests
if (is_array($result)) {
return new JsonResponse(array_map(fn($result) => $result->toArray(), $result));
}

// Single request
return new JsonResponse($result->toArray());
}
}
```
116 changes: 116 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# GraphQL Attribute Schema
Build your GraphQL Schema (for [webonyx/graphql-php](https://github.com/webonyx/graphql-php)) based on attributes.

**Note:** this library is still work in progress, and misses some valuable features (see [todo](todo.md))

## Why this library?
[webonyx/graphql-php](https://github.com/webonyx/graphql-php) requires a `Schema` in order to create a GraphQL Server.
This schema configuration is based on (large) PHP arrays.

Wouldn't it be nice to have a library in between which can read your mutation, query and type classes instead, and create
that schema configuration for you?

This is where *GraphQL Attribute Schema* comes into place. By adding attributes to your classes,
*GraphQL Attribute Schema* will create the schema configuration for you.

## Documentation
- [Getting started](getting_started.md)
- [Usage](usage.md)

## A simple example
```php
use Jerowork\GraphqlAttributeSchema\Attribute\Enum;
use Jerowork\GraphqlAttributeSchema\Attribute\Field;
use Jerowork\GraphqlAttributeSchema\Attribute\InputType;
use Jerowork\GraphqlAttributeSchema\Attribute\Mutation;
use Jerowork\GraphqlAttributeSchema\Attribute\Type;

#[Mutation]
final readonly class CreateUserMutation
{
public function __invoke(CreateUserInputType $input): User
{
// Do your magic; create your user here and return
}
}

#[Query(description: 'Get a user')]
final readonly class UserQuery
{
public function __invoke(int $userid): User
{
// Do your magic; retrieve your user and return
}
}

#[InputType]
final readonly class CreateUserInputType
{
public function __construct(
#[Field]
public int $userId,
#[Field]
public string $name,
#[Field(name: 'phoneNumber')]
public ?string $phone,
) {}
}

#[Type]
final readonly class User
{
// Define fields by property
public function __construct(
#[Field]
public int $userId,
#[Field]
public string $name,
public ?string $phone,
#[Field(description: 'The status of the user')]
public UserStatusType $status,
) {}

// Or define fields by method for additional logic
#[Field]
public function getPhoneNumber(): string
{
return sprintf('+31%s', $this->phone);
}
}

#[Enum(description: 'The status of the user')]
enum UserStatusType: string
{
case Created = 'CREATED';
case Removed = 'REMOVED';
}
```

Will result in the following GraphQL schema:
```graphql
type Mutation {
createUser(input: CreateUserInput!): User!
}

type Query {
user(userId: Int!): User!
}

type CreateUserInput {
userId: Int!
name: String!
phoneNumber: string
}

type User {
userId: Int!
name: String!
status: UserStatus!
phoneNumber: string
}

enum UserStatus {
CREATED
REMOVED
}
```
12 changes: 12 additions & 0 deletions docs/todo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Todo
This library is still work in progress, and misses some valuable features:

- Introduction of `#[Deprecated]` attribute
- Overwrite type via attributes
- Allow simple lists (array type)
- Connection, edge, nodes (see https://relay.dev/graphql/connections.htm)
- Make AST serializable (cacheable)
- Handle `DateTime` and `DateTimeImmutable`
- GraphQL interfaces, inheritance
- Inject autowiring services
- Subscriptions
Loading

0 comments on commit 4795c90

Please sign in to comment.