No longer require name after operation type

This commit is contained in:
Tobe O 2018-08-03 21:41:16 -04:00
parent 0a1928cf26
commit a2454be927
3 changed files with 70 additions and 57 deletions

View file

@ -19,7 +19,7 @@ main() async {
var todoService = app.use('api/todos', new MapService()) as Service; var todoService = app.use('api/todos', new MapService()) as Service;
var api = objectType( var queryType = objectType(
'Query', 'Query',
description: 'A simple API that manages your to-do list.', description: 'A simple API that manages your to-do list.',
fields: [ fields: [
@ -39,7 +39,21 @@ main() async {
], ],
); );
var schema = graphQLSchema(query: api); var mutationType = objectType(
'Mutation',
description: 'Modify the to-do list.',
fields: [
field(
'create',
type: graphQLString,
),
],
);
var schema = graphQLSchema(
query: queryType,
mutation: mutationType,
);
app.all('/graphql', graphQLHttp(new GraphQL(schema))); app.all('/graphql', graphQLHttp(new GraphQL(schema)));
app.get('/graphiql', graphiql()); app.get('/graphiql', graphiql());

View file

@ -1,5 +1,4 @@
import 'dart:io'; import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'package:angel_validate/server.dart'; import 'package:angel_validate/server.dart';
import 'package:dart2_constant/convert.dart'; import 'package:dart2_constant/convert.dart';
@ -13,12 +12,36 @@ final ContentType graphQlContentType =
final Validator graphQlPostBody = new Validator({ final Validator graphQlPostBody = new Validator({
'query*': isNonEmptyString, 'query*': isNonEmptyString,
'operation_name': isNonEmptyString, 'operation_name': isNonEmptyString,
'variables': predicate((v) => v == null || v is Map), 'variables': predicate((v) => v == null || v is String || v is Map),
}); });
RequestHandler graphQLHttp(GraphQL graphQl) { RequestHandler graphQLHttp(GraphQL graphQl) {
return (req, res) async { return (req, res) async {
executeMap(Map map) async {
var text = req.body['query'] as String;
var operationName = req.body['operation_name'] as String;
var variables = req.body['variables'];
if (variables is String) {
variables = json.decode(variables as String);
}
return {
'data': await graphQl.parseAndExecute(
text,
sourceUrl: 'input',
operationName: operationName,
variableValues: foldToStringDynamic(variables as Map),
),
};
}
try { try {
if (req.method == 'GET') {
if (await validateQuery(graphQlPostBody)(req, res)) {
return await executeMap(req.query);
}
} else if (req.method == 'POST') {
if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) { if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) {
var text = utf8.decode(await req.lazyOriginalBuffer()); var text = utf8.decode(await req.lazyOriginalBuffer());
return { return {
@ -26,17 +49,10 @@ RequestHandler graphQLHttp(GraphQL graphQl) {
}; };
} else if (req.headers.contentType?.mimeType == 'application/json') { } else if (req.headers.contentType?.mimeType == 'application/json') {
if (await validate(graphQlPostBody)(req, res)) { if (await validate(graphQlPostBody)(req, res)) {
var text = req.body['query'] as String; return await executeMap(req.body);
var operationName = req.body['operation_name'] as String; }
var variables = req.body['variables'] as Map; } else {
return { throw new AngelHttpException.badRequest();
'data': await graphQl.parseAndExecute(
text,
sourceUrl: 'input',
operationName: operationName,
variableValues: foldToStringDynamic(variables),
),
};
} }
} else { } else {
throw new AngelHttpException.badRequest(); throw new AngelHttpException.badRequest();

View file

@ -56,8 +56,7 @@ class Parser {
else { else {
if (next(TokenType.MUTATION) || next(TokenType.QUERY)) { if (next(TokenType.MUTATION) || next(TokenType.QUERY)) {
var TYPE = current; var TYPE = current;
if (next(TokenType.NAME)) { Token NAME = next(TokenType.NAME) ? current : null;
var NAME = current;
var variables = parseVariableDefinitions(); var variables = parseVariableDefinitions();
var dirs = parseDirectives(); var dirs = parseDirectives();
var selectionSet = parseSelectionSet(); var selectionSet = parseSelectionSet();
@ -67,12 +66,7 @@ class Parser {
..directives.addAll(dirs); ..directives.addAll(dirs);
else else
throw new SyntaxError( throw new SyntaxError(
'Expected selection set in fragment definition.', 'Expected selection set in fragment definition.', NAME.span);
NAME.span);
} else
throw new SyntaxError(
'Expected name after operation type "${TYPE.text}" in operation definition.',
TYPE.span);
} else } else
return null; return null;
} }
@ -142,11 +136,8 @@ class Parser {
ELLIPSIS, ON, typeCondition, selectionSet) ELLIPSIS, ON, typeCondition, selectionSet)
..directives.addAll(directives); ..directives.addAll(directives);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected selection set in inline fragment.',
'Expected selection set in inline fragment.', directives.isEmpty ? typeCondition.span : directives.last.span);
directives.isEmpty
? typeCondition.span
: directives.last.span);
} else } else
throw new SyntaxError( throw new SyntaxError(
'Expected type condition after "on" in inline fragment.', 'Expected type condition after "on" in inline fragment.',
@ -174,8 +165,7 @@ class Parser {
return new SelectionSetContext(LBRACE, current) return new SelectionSetContext(LBRACE, current)
..selections.addAll(selections); ..selections.addAll(selections);
else else
throw new SyntaxError( throw new SyntaxError('Expected "}" after selection set.',
'Expected "}" after selection set.',
selections.isEmpty ? LBRACE.span : selections.last.span); selections.isEmpty ? LBRACE.span : selections.last.span);
} else } else
return null; return null;
@ -287,11 +277,9 @@ class Parser {
if (next(TokenType.RBRACKET)) { if (next(TokenType.RBRACKET)) {
return new ListTypeContext(LBRACKET, type, current); return new ListTypeContext(LBRACKET, type, current);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected "]" in list type.', type.span);
'Expected "]" in list type.', type.span);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected type after "[".', LBRACKET.span);
'Expected type after "[".', LBRACKET.span);
} else } else
return null; return null;
} }
@ -331,8 +319,7 @@ class Parser {
return new DirectiveContext( return new DirectiveContext(
ARROBA, NAME, null, LPAREN, current, arg, null); ARROBA, NAME, null, LPAREN, current, arg, null);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected \')\'', arg.valueOrVariable.span);
'Expected \')\'', arg.valueOrVariable.span);
} else } else
throw new SyntaxError( throw new SyntaxError(
'Expected argument in directive.', LPAREN.span); 'Expected argument in directive.', LPAREN.span);
@ -340,8 +327,7 @@ class Parser {
return new DirectiveContext( return new DirectiveContext(
ARROBA, NAME, null, null, null, null, null); ARROBA, NAME, null, null, null, null, null);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected name for directive.', ARROBA.span);
'Expected name for directive.', ARROBA.span);
} else } else
return null; return null;
} }
@ -363,8 +349,7 @@ class Parser {
if (next(TokenType.RPAREN)) if (next(TokenType.RPAREN))
return out; return out;
else else
throw new SyntaxError( throw new SyntaxError('Expected ")" in argument list.', LPAREN.span);
'Expected ")" in argument list.', LPAREN.span);
} else } else
return []; return [];
} }
@ -420,8 +405,7 @@ class Parser {
if (value != null) { if (value != null) {
return new DefaultValueContext(EQUALS, value); return new DefaultValueContext(EQUALS, value);
} else } else
throw new SyntaxError( throw new SyntaxError('Expected value after "=" sign.', EQUALS.span);
'Expected value after "=" sign.', EQUALS.span);
} else } else
return null; return null;
} }
@ -474,8 +458,7 @@ class Parser {
if (next(TokenType.RBRACKET)) { if (next(TokenType.RBRACKET)) {
return new ArrayValueContext(LBRACKET, current)..values.addAll(values); return new ArrayValueContext(LBRACKET, current)..values.addAll(values);
} else } else
throw new SyntaxError( throw new SyntaxError('Unterminated array literal.', LBRACKET.span);
'Unterminated array literal.', LBRACKET.span);
} else } else
return null; return null;
} }