No longer require name after operation type
This commit is contained in:
parent
0a1928cf26
commit
a2454be927
3 changed files with 70 additions and 57 deletions
|
@ -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());
|
||||||
|
|
|
@ -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,30 +12,47 @@ 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.headers.contentType?.mimeType == graphQlContentType.mimeType) {
|
if (req.method == 'GET') {
|
||||||
var text = utf8.decode(await req.lazyOriginalBuffer());
|
if (await validateQuery(graphQlPostBody)(req, res)) {
|
||||||
return {
|
return await executeMap(req.query);
|
||||||
'data': await graphQl.parseAndExecute(text, sourceUrl: 'input')
|
}
|
||||||
};
|
} else if (req.method == 'POST') {
|
||||||
} else if (req.headers.contentType?.mimeType == 'application/json') {
|
if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) {
|
||||||
if (await validate(graphQlPostBody)(req, res)) {
|
var text = utf8.decode(await req.lazyOriginalBuffer());
|
||||||
var text = req.body['query'] as String;
|
|
||||||
var operationName = req.body['operation_name'] as String;
|
|
||||||
var variables = req.body['variables'] as Map;
|
|
||||||
return {
|
return {
|
||||||
'data': await graphQl.parseAndExecute(
|
'data': await graphQl.parseAndExecute(text, sourceUrl: 'input')
|
||||||
text,
|
|
||||||
sourceUrl: 'input',
|
|
||||||
operationName: operationName,
|
|
||||||
variableValues: foldToStringDynamic(variables),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
|
} 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 {
|
} else {
|
||||||
throw new AngelHttpException.badRequest();
|
throw new AngelHttpException.badRequest();
|
||||||
|
|
|
@ -56,23 +56,17 @@ 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();
|
if (selectionSet != null)
|
||||||
if (selectionSet != null)
|
return new OperationDefinitionContext(
|
||||||
return new OperationDefinitionContext(
|
TYPE, NAME, variables, selectionSet)
|
||||||
TYPE, NAME, variables, selectionSet)
|
..directives.addAll(dirs);
|
||||||
..directives.addAll(dirs);
|
else
|
||||||
else
|
|
||||||
throw new SyntaxError(
|
|
||||||
'Expected selection set in fragment definition.',
|
|
||||||
NAME.span);
|
|
||||||
} else
|
|
||||||
throw new SyntaxError(
|
throw new SyntaxError(
|
||||||
'Expected name after operation type "${TYPE.text}" in operation definition.',
|
'Expected selection set in fragment definition.', NAME.span);
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue