platform/angel_graphql/lib/src/graphql_http.dart

108 lines
3.4 KiB
Dart
Raw Normal View History

2018-08-02 17:02:00 +00:00
import 'dart:io';
2018-08-04 19:18:53 +00:00
2018-08-02 17:02:00 +00:00
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_validate/server.dart';
import 'package:dart2_constant/convert.dart';
2018-08-03 21:07:08 +00:00
import 'package:graphql_parser/graphql_parser.dart';
import 'package:graphql_schema/graphql_schema.dart';
2018-08-02 17:02:00 +00:00
import 'package:graphql_server/graphql_server.dart';
final ContentType graphQlContentType =
new ContentType('application', 'graphql');
final Validator graphQlPostBody = new Validator({
'query*': isNonEmptyString,
'operation_name': isNonEmptyString,
'variables': predicate((v) => v == null || v is String || v is Map),
2018-08-02 17:02:00 +00:00
});
/// A [RequestHandler] that serves a spec-compliant GraphQL backend.
///
/// Follows the guidelines listed here:
/// https://graphql.org/learn/serving-over-http/
RequestHandler graphQLHttp(GraphQL graphQL) {
2018-08-02 17:02:00 +00:00
return (req, res) async {
var globalVariables = <String, dynamic>{
'__requestctx': req,
'__responsectx': res,
};
executeMap(Map map) async {
2018-11-01 21:27:36 +00:00
var body = await req.parseBody();
var text = body['query'] as String;
var operationName = body['operation_name'] as String;
var variables = 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),
globalVariables: globalVariables,
),
};
}
2018-08-03 21:07:08 +00:00
try {
if (req.method == 'GET') {
2018-11-01 21:27:36 +00:00
if (await validateQuery(graphQlPostBody)(req, res) as bool) {
return await executeMap(await req.parseQuery());
}
} else if (req.method == 'POST') {
if (req.headers.contentType?.mimeType == graphQlContentType.mimeType) {
2018-11-01 21:27:36 +00:00
var text = utf8.decode(await req.parseRawRequestBuffer());
2018-08-03 21:07:08 +00:00
return {
'data': await graphQL.parseAndExecute(
text,
sourceUrl: 'input',
globalVariables: globalVariables,
),
2018-08-03 21:07:08 +00:00
};
} else if (req.headers.contentType?.mimeType == 'application/json') {
2018-11-01 21:27:36 +00:00
if (await validate(graphQlPostBody)(req, res) as bool) {
return await executeMap(await req.parseBody());
}
} else {
throw new AngelHttpException.badRequest();
2018-08-03 21:07:08 +00:00
}
} else {
throw new AngelHttpException.badRequest();
2018-08-02 17:02:00 +00:00
}
} on ValidationException catch (e) {
var errors = <GraphQLExceptionError>[
new GraphQLExceptionError(e.message)
];
errors
.addAll(e.errors.map((ee) => new GraphQLExceptionError(ee)).toList());
return new GraphQLException(errors).toJson();
2018-08-03 21:07:08 +00:00
} on AngelHttpException catch (e) {
var errors = <GraphQLExceptionError>[
new GraphQLExceptionError(e.message)
];
errors
.addAll(e.errors.map((ee) => new GraphQLExceptionError(ee)).toList());
2018-08-03 23:30:19 +00:00
return new GraphQLException(errors).toJson();
2018-08-03 21:07:08 +00:00
} on SyntaxError catch (e) {
return new GraphQLException.fromSourceSpan(e.message, e.span);
} on GraphQLException catch (e) {
return e.toJson();
2018-08-04 19:18:53 +00:00
} catch (e, st) {
if (req.app?.logger != null) {
req.app.logger.severe(
'An error occurred while processing GraphQL query at ${req.uri}.',
e,
st);
}
2018-08-03 21:07:08 +00:00
return new GraphQLException.fromMessage(e.toString()).toJson();
2018-08-02 17:02:00 +00:00
}
};
}