angel_graphql 1.0.0-alpha

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 34

Logo


Pub Pub

A complete implementation of the official GraphQL specification - these are the Angel framework-specific bindings.

The goal of this project is to provide to server-side users of Dart an alternative to REST API's. package:angel_graphql, which, when combined with the allows server-side Dart users to build backends with GraphQL and virtually any database imaginable.

Installation

To install package:angel_graphql, add the following to your pubspec.yaml:

dependencies:
    angel_framework: ^2.0.0-alpha
    angel_graphql: ^1.0.0-alpha

Usage

Using this package is very similar to GraphQL.js - you define a schema, and then mount graphQLHttp in your router to start serving. This implementation supports GraphQL features like introspection, so you can play around with graphiql as well!

Firstly, define your schema. A GraphQL schema contains an object type that defines all querying operations that can be applied to the backend.

A GraphQL schema may also have a mutation object type, which defines operations that change the backend's state, and optionally a subscription type, which defines real-time interactions (coming soon!).

You can use the convertDartType helper to wrap your existing Model/PODO classes, and make GraphQL aware of them without duplicated effort.

import 'package:angel_framework/angel_framework.dart';
import 'package:angel_graphql/angel_graphql.dart';
import 'package:graphql_schema/graphql_schema.dart';
import 'package:graphql_server/graphql_server.dart';
import 'package:graphql_server/mirrors.dart';

Future configureServer(Angel app) async {
    var queryType = objectType(
        'Query',
        description: 'A simple API that manages your to-do list.',
        fields: [
            field(
                'todos',
                listOf(convertDartType(Todo).nonNullable()),
                resolve: resolveViaServiceIndex(todoService),
            ),
            field(
                'todo',
                convertDartType(Todo),
                resolve: resolveViaServiceRead(todoService),
                inputs: [
                    new GraphQLFieldInput('id', graphQLId.nonNullable()),
                ],
            ),
        ],
    );

    var mutationType = objectType(
        'Mutation',
        description: 'Modify the to-do list.',
        fields: [
            field(
                'create',
                graphQLString,
            ),
        ],
    );

    var schema = graphQLSchema(
        queryType: queryType,
        mutationType: mutationType,
    );
}

After you've created your GraphQLSchema, you just need to wrap in a call to graphQLHttp, a request handler that responds to GraphQL.

In development, it's also highly recommended to mount the graphiQL handler, which serves GraphQL's official visual interface, for easy querying and feedback.

app.all('/graphql', graphQLHttp(new GraphQL(schema)));
app.get('/graphiql', graphiQL());

All that's left now is just to start the server!

var server = await http.startServer('127.0.0.1', 3000);
var uri =
    new Uri(scheme: 'http', host: server.address.address, port: server.port);
var graphiqlUri = uri.replace(path: 'graphiql');
print('Listening at $uri');
print('Access graphiql at $graphiqlUri');

Visit your /graphiql endpoint, and you'll see the graphiql UI, ready-to-go!

Graphiql screenshot

Now you're ready to build a GraphQL API!

Using Services

What would Angel be without services? For those unfamiliar - in Angel, Service is a base class that implements CRUD functionality, and serves as the database interface within an Angel application. They are well-suited for NoSQL or other databases without a schema (they can be used with SQL, but that's not their primary focus).

package:angel_graphql has functionality to resolve fields by interacting with services.

Consider our previous example, and note the calls to resolveViaServiceIndex and resolveViaServiceRead:

var queryType = objectType(
    'Query',
    description: 'A simple API that manages your to-do list.',
    fields: [
      field(
        'todos',
        listOf(convertDartType(Todo).nonNullable()),
        resolve: resolveViaServiceIndex(todoService),
      ),
      field(
        'todo',
        convertDartType(Todo),
        resolve: resolveViaServiceRead(todoService),
        inputs: [
          new GraphQLFieldInput('id', graphQLId.nonNullable()),
        ],
      ),
    ],
  );

In all, there are:

  • resolveViaServiceIndex
  • resolveViaServiceFindOne
  • resolveViaServiceRead
  • resolveViaServiceModify
  • resolveViaServiceUpdate
  • resolveViaServiceRemove

As one might imagine, using these convenience helpers makes it much quicker to implement CRUD functionality in a GraphQL API.

Documentation

The convertDartType function can automatically read the documentation from a type like the following:

@GraphQLDocumentation(description: 'Any object with a .text (String) property.')
abstract class HasText {
  String get text;
}

@serializable
@GraphQLDocumentation(
    description: 'A task that might not be completed yet. **Yay! Markdown!**')
class Todo extends Model implements HasText {
  String text;

  @GraphQLDocumentation(deprecationReason: 'Use `completion_status` instead.')
  bool completed;

  CompletionStatus completionStatus;

  Todo({this.text, this.completed, this.completionStatus});
}

@GraphQLDocumentation(description: 'The completion status of a to-do item.')
enum CompletionStatus { COMPLETE, INCOMPLETE }

You can also manually provide documentation for parameters and endpoints, via a description parameter on almost all related functions.

See package:graphql_schema for more documentation.

1.0.0-alpha

  • First official release.

example/main.dart

import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/http.dart';
import 'package:angel_graphql/angel_graphql.dart';
import 'package:angel_serialize/angel_serialize.dart';
import 'package:graphql_schema/graphql_schema.dart';
import 'package:graphql_server/graphql_server.dart';
import 'package:graphql_server/mirrors.dart';
import 'package:logging/logging.dart';

main() async {
  var app = new Angel();
  var http = new AngelHttp(app);
  hierarchicalLoggingEnabled = true;
  app.logger = new Logger('angel_graphql')
    ..onRecord.listen((rec) {
      print(rec);
      if (rec.error != null) print(rec.error);
      if (rec.stackTrace != null) print(rec.stackTrace);
    });

  var todoService = app.use('api/todos', new MapService());

  var queryType = objectType(
    'Query',
    description: 'A simple API that manages your to-do list.',
    fields: [
      field(
        'todos',
        listOf(convertDartType(Todo).nonNullable()),
        resolve: resolveViaServiceIndex(todoService),
      ),
      field(
        'todo',
        convertDartType(Todo),
        resolve: resolveViaServiceRead(todoService),
        inputs: [
          new GraphQLFieldInput('id', graphQLId.nonNullable()),
        ],
      ),
    ],
  );

  var mutationType = objectType(
    'Mutation',
    description: 'Modify the to-do list.',
    fields: [
      field(
        'create',
        graphQLString,
      ),
    ],
  );

  var schema = graphQLSchema(
    queryType: queryType,
    mutationType: mutationType,
  );

  app.all('/graphql', graphQLHttp(new GraphQL(schema)));
  app.get('/graphiql', graphiQL());

  await todoService
      .create({'text': 'Clean your room!', 'completion_status': 'COMPLETE'});
  await todoService.create(
      {'text': 'Take out the trash', 'completion_status': 'INCOMPLETE'});
  await todoService.create({
    'text': 'Become a billionaire at the age of 5',
    'completion_status': 'INCOMPLETE'
  });

  var server = await http.startServer('127.0.0.1', 3000);
  var uri =
      new Uri(scheme: 'http', host: server.address.address, port: server.port);
  var graphiqlUri = uri.replace(path: 'graphiql');
  print('Listening at $uri');
  print('Access graphiql at $graphiqlUri');
}

@GraphQLDocumentation(description: 'Any object with a .text (String) property.')
abstract class HasText {
  String get text;
}

@serializable
@GraphQLDocumentation(
    description: 'A task that might not be completed yet. **Yay! Markdown!**')
class Todo extends Model implements HasText {
  String text;

  @GraphQLDocumentation(deprecationReason: 'Use `completion_status` instead.')
  bool completed;

  CompletionStatus completionStatus;

  Todo({this.text, this.completed, this.completionStatus});
}

@GraphQLDocumentation(description: 'The completion status of a to-do item.')
enum CompletionStatus { COMPLETE, INCOMPLETE }

Use this package as a library

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  angel_graphql: ^1.0.0-alpha

2. Install it

You can install packages from the command line:

with pub:


$ pub get

Alternatively, your editor might support pub get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:angel_graphql/angel_graphql.dart';
  
Version Uploaded Documentation Archive
1.0.0-alpha Nov 2, 2018 Go to the documentation of angel_graphql 1.0.0-alpha Download angel_graphql 1.0.0-alpha archive
Popularity:
Describes how popular the package is relative to other packages. [more]
27
Health:
Code health derived from static analysis. [more]
18
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
75
Overall:
Weighted score of the above. [more]
34
Learn more about scoring.

We analyzed this package on Jan 15, 2019, and provided a score, details, and suggestions below. Analysis was completed with status completed using:

  • Dart: 2.1.0
  • pana: 0.12.10

Platforms

Detected platforms:

Low code quality prevents platform classification.

Health issues and suggestions

Fix lib/src/graphql_http.dart. (-82.20 points)

Analysis of lib/src/graphql_http.dart failed with 6 errors, including:

line 31 col 22: The expression here has a type of 'void', and therefore cannot be used.

line 32 col 31: The expression here has a type of 'void', and therefore cannot be used.

line 33 col 27: The expression here has a type of 'void', and therefore cannot be used.

line 53 col 45: The method 'parseQuery' isn't defined for the class 'RequestContext'.

line 57 col 44: The method 'parseRawRequestBuffer' isn't defined for the class 'RequestContext'.

Maintenance issues and suggestions

Fix platform conflicts. (-20 points)

Low code quality prevents platform classification.

Package is pre-release. (-5 points)

Pre-release versions should be used with caution, their API may change in breaking ways.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=2.0.0-dev <3.0.0
angel_framework ^2.0.0-alpha 2.0.0-alpha.18
angel_validate ^2.0.0-alpha 2.0.1
graphql_parser ^1.0.0 1.1.1
graphql_schema ^1.0.0 1.0.1
graphql_server ^1.0.0-beta 1.0.0-beta
http_parser ^3.0.0 3.1.3
Transitive dependencies
angel_container 1.0.0
angel_http_exception 1.0.0+3
angel_model 1.0.1
angel_route 3.0.1
charcode 1.1.2
code_buffer 1.0.1
collection 1.14.11
combinator 1.1.0
convert 2.1.1
crypto 2.0.6
dart2_constant 1.0.2+dart2
file 5.0.7
http2 1.0.0
http_server 0.9.8+1
intl 0.15.7
matcher 0.12.4
merge_map 1.0.2
meta 1.1.7
mime 0.9.6+2
mock_request 1.0.4
path 1.6.2
quiver 2.0.1
quiver_hashcode 2.0.0
recase 2.0.0+1
source_span 1.5.1
stack_trace 1.9.3
string_scanner 1.0.4
term_glyph 1.1.0
tuple 1.0.2
typed_data 1.1.6
uuid 2.0.0-rc1
Dev dependencies
angel_serialize ^2.0.0 2.2.1+2
logging ^0.11.0 0.11.3+2