diff --git a/angel_graphql/example/main.dart b/angel_graphql/example/main.dart index 3e3de3bd..84452d8a 100644 --- a/angel_graphql/example/main.dart +++ b/angel_graphql/example/main.dart @@ -19,16 +19,20 @@ main() async { var todoService = app.use('api/todos', new MapService()) as Service; - var api = objectType('api', fields: [ - field( - 'todo', - type: listType(objectTypeFromDartType(Todo)), - resolve: resolveFromService(todoService), - arguments: [ - new GraphQLFieldArgument('id', graphQLId), - ], - ), - ]); + var api = objectType( + 'Query', + description: 'A simple API that manages your to-do list.', + fields: [ + field( + 'todo', + type: listType(objectTypeFromDartType(Todo).nonNullable()), + resolve: resolveFromService(todoService), + arguments: [ + new GraphQLFieldArgument('id', graphQLId), + ], + ), + ], + ); var schema = graphQLSchema(query: api); @@ -37,7 +41,8 @@ main() async { await todoService.create({'text': 'Clean your room!', 'completed': true}); await todoService.create({'text': 'Take out the trash', 'completed': false}); - await todoService.create({'text': 'Become a billionaire at the age of 5', 'completed': false}); + await todoService.create( + {'text': 'Become a billionaire at the age of 5', 'completed': false}); var server = await http.startServer('127.0.0.1', 3000); var uri = @@ -48,6 +53,7 @@ main() async { } @serializable +@GraphQLDocumentation(description: 'A task that might not be completed yet. **Yay! Markdown!**') class Todo extends Model { String text; diff --git a/graphql_schema/lib/src/gen.dart b/graphql_schema/lib/src/gen.dart index 792b859d..91b79c04 100644 --- a/graphql_schema/lib/src/gen.dart +++ b/graphql_schema/lib/src/gen.dart @@ -11,7 +11,11 @@ GraphQLObjectType objectType(String name, GraphQLField field(String name, {Iterable> arguments: const [], GraphQLFieldResolver resolve, - GraphQLType type}) { + GraphQLType type, + String deprecationReason}) { return new GraphQLField(name, - arguments: arguments, resolve: resolve, type: type); + arguments: arguments, + resolve: resolve, + type: type, + deprecationReason: deprecationReason); } diff --git a/graphql_schema/lib/src/schema.dart b/graphql_schema/lib/src/schema.dart index 98bf6a92..0b3d88e6 100644 --- a/graphql_schema/lib/src/schema.dart +++ b/graphql_schema/lib/src/schema.dart @@ -1,13 +1,21 @@ library graphql_schema.src.schema; import 'dart:async'; + import 'package:meta/meta.dart'; + part 'argument.dart'; + part 'field.dart'; + part 'gen.dart'; + part 'object_type.dart'; + part 'scalar.dart'; + part 'type.dart'; + part 'validation_result.dart'; class GraphQLSchema { @@ -19,8 +27,11 @@ class GraphQLSchema { } GraphQLSchema graphQLSchema( - {@required GraphQLObjectType query, GraphQLObjectType mutation, GraphQLObjectType subscription}) => - new GraphQLSchema(query: query, mutation: mutation, subscription: subscription); + {@required GraphQLObjectType query, + GraphQLObjectType mutation, + GraphQLObjectType subscription}) => + new GraphQLSchema( + query: query, mutation: mutation, subscription: subscription); /// A default resolver that always returns `null`. resolveToNull(_, __) => null; @@ -31,3 +42,10 @@ class GraphQLException extends FormatException { @override String toString() => 'GraphQL exception: $message'; } + +/// A metadata annotation used to provide documentation to `package:graphql_server`. +class GraphQLDocumentation { + final String description; + + const GraphQLDocumentation({this.description}); +} diff --git a/graphql_server/lib/mirrors.dart b/graphql_server/lib/mirrors.dart index 329a0d9d..725bc612 100644 --- a/graphql_server/lib/mirrors.dart +++ b/graphql_server/lib/mirrors.dart @@ -65,6 +65,7 @@ GraphQLObjectType objectTypeFromClassMirror(ClassMirror mirror) { return objectType( MirrorSystem.getName(mirror.simpleName), fields: fields, + description: _getDescription(mirror.metadata), ); } @@ -83,6 +84,7 @@ GraphQLField fieldFromGetter( return field( nameString, type: type, + deprecationReason: _getDeprecationReason(mirror.metadata), resolve: (obj, _) { if (obj is Map && exclude?.canSerialize != true) { return obj[nameString]; @@ -152,3 +154,27 @@ bool _autoNames(ClassMirror clazz) { return false; } + +String _getDeprecationReason(List metadata) { + for (var obj in metadata) { + if (obj.reflectee is Deprecated) { + var expires = (obj.reflectee as Deprecated).expires; + + if (expires == deprecated.expires) { + return 'Expires after $expires'; + } else { + deprecated.expires; + } + } + } +} + +String _getDescription(List metadata) { + for (var obj in metadata) { + if (obj.reflectee is GraphQLDocumentation) { + return (obj.reflectee as GraphQLDocumentation).description; + } + } + + return null; +}