The XOOM GraphQL server for smooth legacy integration with complex queries made simple.
The XOOM GraphQL server component is based on XOOM HTTP. The GraphQLResource is a dynamic resource handler implemented as the Reactive HTTP endpoint used to submit queries to our GraphQL server for asynchronous execution. The GraphQLResource registers the URL /graphql as the only HTTP resource specific to GraphQL applications, and thus handles all GraphQL operations. The single endpoint is logical and actually scales with a configurable number of backing actors. As expected, our GraphQL server is end-to-end Reactive.
Queries and Mutations
Queries can be as simple as asking for specific fields and/or nested fields on objects. Queries can accept arguments to fields.
More advanced concepts such as aliases, fragments, operation name, variables, and directives are supported as well. While queries perform data fetching, mutations perform state transformations. The following is a basic example of a find query handled by our GraphQL server:
query { bookById(id: "book-1") { id name pageCount author { firstName lastName } }}
And the following is an example of mutation on a resource entity. The upsert query means to insert or update as needed, making it an idempotent operation:
mutation { upsertBook(id: "book-8", name: "The Mysterious Stranger", pageCount: 200, authorId: "author-2") { id name pageCount author { firstName lastName } }}
Schemas and Types
XOOM GraphQL adopts a schema-first approach. The design of a GraphQL API starts with defining a schema. The grammar used for writing schemas is called Schema Definition Language (SDL). A schema definition supports all GraphQL concepts, such as object types, fields, arguments, scalar types, enumeration types, lists and non-null, as well as interfaces and union types. Server side integration with a specific schema is done by following naming conventions. Classes and methods must match with schema definition components. Queries are validated, and any validation mismatches are signaled as failures. Here is an example schema:
# The Root Query for the applicationtypeQuery { bookById(id: ID): Book}# The Root Mutation for the applicationtypeMutation { upsertBook(id: ID!, name: String!, pageCount: Int, authorId: ID!): Book}typeBook { id: ID name: String pageCount: Int author: Author}typeAuthor { id: ID firstName: String lastName: String}
The schema types Book and Author map to class Book and Author, respectively:
The next topic is resolvers, which link data query results to schemas.
Resolvers
Each query or mutation must have a resolver that is associated by a naming convention. A resolver is responsible for actually performing a specific operation. All resolvers are registered to a GraphQLProcessor. The GraphQLProcessor is used by the previously discussed GraphQLResource. The GraphProcessor is fully Reactive, being implemented as an actor.
This is a basic (and incomplete) query resolver type:
XOOM GraphQL supports seamless client side integration that makes for smooth query and mutation operations. There are generated classes for types, queries, mutations, requests, responses, and projections. Both the server side and client side are fully Reactive. Our Reactive HTTP client provided by XOOM HTTP can use the generated classes end-to-end.
The following is an example of a Reactive client consuming a GraphQL response from a query that is executed reactively; note the use of .andFinallyConsume(...):