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 api = objectType(
var queryType = objectType(
'Query',
description: 'A simple API that manages your to-do list.',
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.get('/graphiql', graphiql());

View file

@ -1,5 +1,4 @@
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_validate/server.dart';
import 'package:dart2_constant/convert.dart';
@ -13,30 +12,47 @@ final ContentType graphQlContentType =
final Validator graphQlPostBody = new Validator({
'query*': 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) {
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 {
if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) {
var text = utf8.decode(await req.lazyOriginalBuffer());
return {
'data': await graphQl.parseAndExecute(text, sourceUrl: 'input')
};
} else if (req.headers.contentType?.mimeType == 'application/json') {
if (await validate(graphQlPostBody)(req, res)) {
var text = req.body['query'] as String;
var operationName = req.body['operation_name'] as String;
var variables = req.body['variables'] as Map;
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) {
var text = utf8.decode(await req.lazyOriginalBuffer());
return {
'data': await graphQl.parseAndExecute(
text,
sourceUrl: 'input',
operationName: operationName,
variableValues: foldToStringDynamic(variables),
),
'data': await graphQl.parseAndExecute(text, sourceUrl: 'input')
};
} else if (req.headers.contentType?.mimeType == 'application/json') {
if (await validate(graphQlPostBody)(req, res)) {
return await executeMap(req.body);
}
} else {
throw new AngelHttpException.badRequest();
}
} else {
throw new AngelHttpException.badRequest();

View file

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