This is an automated email from the ASF dual-hosted git repository. shuber pushed a commit to branch UNOMI-180-CXS-GRAPHQLAPI in repository https://gitbox.apache.org/repos/asf/unomi.git
commit 5e21cbc7003b4ef069c7df5e73bb65221edc7841 Author: sergehuber <shu...@jahia.com> AuthorDate: Mon May 13 11:59:36 2019 +0200 UNOMI-180 CDP Specification implementation - Implement GET and POST basic support - Add support for schema retrieval - Add extended scalars (some scalars are not implemented yet such as GeoPoint) --- graphql/cxs-impl/pom.xml | 6 + .../unomi/graphql/internal/CDPSDLServletImpl.java | 146 ++++++++++++++++++++- .../src/main/resources/cdp-schema.graphqls | 6 +- graphql/karaf-feature/pom.xml | 5 + graphql/pom.xml | 1 + 5 files changed, 155 insertions(+), 9 deletions(-) diff --git a/graphql/cxs-impl/pom.xml b/graphql/cxs-impl/pom.xml index 79cd629..e4e093e 100644 --- a/graphql/cxs-impl/pom.xml +++ b/graphql/cxs-impl/pom.xml @@ -50,6 +50,12 @@ <scope>provided</scope> </dependency> <dependency> + <groupId>com.graphql-java</groupId> + <artifactId>graphql-java-extended-scalars</artifactId> + <version>${graphql.java.extended.scalars.version}</version> + <scope>provided</scope> + </dependency> + <dependency> <groupId>org.osgi</groupId> <artifactId>osgi.enterprise</artifactId> <version>6.0.0</version> diff --git a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java index 8cafa15..df69692 100644 --- a/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java +++ b/graphql/cxs-impl/src/main/java/org/apache/unomi/graphql/internal/CDPSDLServletImpl.java @@ -16,8 +16,17 @@ */ package org.apache.unomi.graphql.internal; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.google.common.base.Charsets; -import graphql.schema.GraphQLSchema; +import graphql.ExecutionInput; +import graphql.ExecutionResult; +import graphql.GraphQL; +import graphql.TypeResolutionEnvironment; +import graphql.introspection.IntrospectionQuery; +import graphql.scalars.ExtendedScalars; +import graphql.schema.*; import graphql.schema.idl.RuntimeWiring; import graphql.schema.idl.SchemaGenerator; import graphql.schema.idl.SchemaParser; @@ -29,9 +38,11 @@ import org.osgi.service.component.annotations.Component; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.*; +import java.util.HashMap; +import java.util.Map; @Component( service={javax.servlet.http.HttpServlet.class,javax.servlet.Servlet.class}, @@ -40,6 +51,9 @@ import java.io.Reader; public class CDPSDLServletImpl extends HttpServlet { private BundleContext bundleContext; + private ObjectMapper objectMapper; + private GraphQL graphQL; + @Activate void activate(BundleContext bundleContext) { @@ -47,7 +61,77 @@ public class CDPSDLServletImpl extends HttpServlet { } RuntimeWiring buildRuntimeWiring() { + + GraphQLScalarType emptyTypeWorkAroundScalarType = GraphQLScalarType.newScalar() + .name("EmptyTypeWorkAround") + .description("A marker type to get around the limitation of GraphQL that doesn't allow empty types. It should be always ignored.") + .coercing(new Coercing() { + @Override + public Object serialize(Object dataFetcherResult) throws CoercingSerializeException { + return null; + } + + @Override + public Object parseValue(Object input) throws CoercingParseValueException { + return input; + } + + @Override + public Object parseLiteral(Object input) throws CoercingParseLiteralException { + return input; + } + }) + .build(); + + GraphQLScalarType geopointScalarType = GraphQLScalarType.newScalar() + .name("GeoPoint") + .description("A type that represents a geographical location") + .coercing(new Coercing() { + @Override + public Object serialize(Object dataFetcherResult) throws CoercingSerializeException { + return null; + } + + @Override + public Object parseValue(Object input) throws CoercingParseValueException { + return input; + } + + @Override + public Object parseLiteral(Object input) throws CoercingParseLiteralException { + return input; + } + }) + .build(); + return RuntimeWiring.newRuntimeWiring() + .scalar(ExtendedScalars.DateTime) + .scalar(ExtendedScalars.Date) + .scalar(ExtendedScalars.Json) + .scalar(ExtendedScalars.Time) + .scalar(emptyTypeWorkAroundScalarType) + .scalar(geopointScalarType) + .type("CDP_EventInterface", typeWiring -> typeWiring + .typeResolver(new TypeResolver() { + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment env) { + return null; + } + })) + .type("CDP_ProfileInterface", typeWiring -> typeWiring + .typeResolver(new TypeResolver() { + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment env) { + return null; + } + })) + .type("CDP_PropertyInterface", typeWiring -> typeWiring + .typeResolver(new TypeResolver() { + @Override + public GraphQLObjectType getType(TypeResolutionEnvironment env) { + return null; + } + })) // .scalar(CustomScalar) // this uses builder function lambda syntax /* @@ -93,6 +177,60 @@ public class CDPSDLServletImpl extends HttpServlet { RuntimeWiring wiring = buildRuntimeWiring(); GraphQLSchema graphQLSchema = schemaGenerator.makeExecutableSchema(typeRegistry, wiring); + graphQL = GraphQL.newGraphQL(graphQLSchema) + .build(); + + objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + } + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + String query = req.getParameter("query"); + if ("/schema.json".equals(req.getPathInfo())) { + query = IntrospectionQuery.INTROSPECTION_QUERY; + } + String operationName = req.getParameter("operationName"); + String variableStr = req.getParameter("variables"); + Map<String, Object> variables = new HashMap<>(); + if ((variableStr != null) && (variableStr.trim().length() > 0)) { + TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() { + }; + variables = objectMapper.readValue(variableStr, typeRef); + } + + executeGraphQLRequest(resp, query, operationName, variables); + } + + private void executeGraphQLRequest(HttpServletResponse resp, String query, String operationName, Map<String, Object> variables) throws IOException { + ExecutionInput executionInput = ExecutionInput.newExecutionInput() + .query(query) + .variables(variables) + .operationName(operationName) + .build(); + + ExecutionResult executionResult = graphQL.execute(executionInput); + + Map<String, Object> toSpecificationResult = executionResult.toSpecification(); + + PrintWriter out = resp.getWriter(); + objectMapper.writeValue(out, toSpecificationResult); + } + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + InputStream bodyStream = req.getInputStream(); + TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() { + }; + Map<String, Object> body = objectMapper.readValue(bodyStream, typeRef); + String query = (String) body.get("query"); + String operationName = (String) body.get("operationName"); + Map<String, Object> variables = (Map<String, Object>) body.get("variables"); + if (variables == null) { + variables = new HashMap<>(); + } + + executeGraphQLRequest(resp, query, operationName, variables); } private Reader getSchemaReader(String resourceUrl) { diff --git a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls b/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls index 7a924ca..6e178a6 100644 --- a/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls +++ b/graphql/cxs-impl/src/main/resources/cdp-schema.graphqls @@ -971,8 +971,4 @@ Uses RFC-3339 representation, for example 16:39:57-08:00, see https://github.com/graphql-java/graphql-java-extended-scalars for example implementation """ -scalar Time - -"""The `Upload` scalar type represents a file upload.""" -scalar Upload - +scalar Time \ No newline at end of file diff --git a/graphql/karaf-feature/pom.xml b/graphql/karaf-feature/pom.xml index b813872..ae56dd4 100644 --- a/graphql/karaf-feature/pom.xml +++ b/graphql/karaf-feature/pom.xml @@ -115,6 +115,11 @@ <version>${graphql.java.annotations.version}</version> </dependency> <dependency> + <groupId>com.graphql-java</groupId> + <artifactId>graphql-java-extended-scalars</artifactId> + <version>${graphql.java.extended.scalars.version}</version> + </dependency> + <dependency> <groupId>org.apache.unomi</groupId> <artifactId>cdp-graphql-api-impl</artifactId> <version>1.4.0-SNAPSHOT</version> diff --git a/graphql/pom.xml b/graphql/pom.xml index 260f787..26f1644 100644 --- a/graphql/pom.xml +++ b/graphql/pom.xml @@ -34,6 +34,7 @@ <graphql.java.servlet.version>7.4.1</graphql.java.servlet.version> <graphql.java.version>12.0</graphql.java.version> <graphql.java.annotations.version>7.0</graphql.java.annotations.version> + <graphql.java.extended.scalars.version>1.0</graphql.java.extended.scalars.version> <jackson.version>2.9.7</jackson.version> </properties>