Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Committed Software
Committed Software

Posted on • Originally published atcommitted.software on

     

First impressions with GraphQL in Java

GraphQL-Java

GraphQL is an open query language for exposing data in a flexible way. It was developed byFacebook and now in production use in manyprojects. The main concepts are that GraphQL describes the data available and then the consumer can ask for what they need. All using the same endpoint and language.

We are investigating its use to expose natural language processing results to replace, or augment,REST.

Java ecosystem

GraphQL is programming language agnostic and different implementations exist inmany languages for this project we are using Java and Spring Boot so the natural choice isgraphql-java. It may not be the only java implementation but it is certainly the most active at this time. This core project stays true to the specification and there are a number of supportingprojects to ease integration and use.

Approach

In GraphQL you need to declare your data schema so clients can introspect the system and query correctly. However, the schema needs to be an accurate representation of your underlying data classes. While you could create both of these things manually, generating one from the other will reduce effort and errors. One approach is to define your schema and generate the data classes. This approach is provided bygraphql-apigen andgraphql-java-tools. While this approach could be very useful if you have a new project with a strict schema specification, we already have data classes. Therefore, we take the classes-first approach and generate the schema. There is agraphql-java-annotations project based on this approach, however, development of it seems to have stopped and the community seems to be moving towardsgraphgql-spqr (pronounced “speaker”). It looks likely that this will become the official graphql-java class-first approach.

Getting started

It was very easy to get started using thegraphql-spring-boot. This gives:

  • A graphql-java servlet, to serve the schema, and accept GET and POST GraphQL requests
  • AGraphiQL UI, for writing and executing GraphQL queries against the published schema.
  • grapghql-java-tools schema first
  • graphql spring common class first

We chose not to use the latter and added graphql-spqr simple by providing agraphql.schema.GraphQLSchema Bean generated using graphql-spqr and annotations onDemoService and the POJOs used.

package io.committed;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.ComponentScan;import org.springframework.stereotype.Controller;import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;import graphql.schema.GraphQLSchema;import io.committed.query.DemoService;import io.leangen.graphql.GraphQLSchemaGenerator;@Controller@EnableAutoConfiguration@ComponentScanpublic class GrahpQLDemo {  @Autowired  DemoService demoService;  @Bean  GraphQLSchema schema() {    return new GraphQLSchemaGenerator()        .withOperationsFromSingleton(demoService)        .generate();  }  public static void main(String[] args) throws Exception {    SpringApplication.run(GrahpQLDemo.class, args);  }}

Getting going

It was simple to add the graphql-spqr annotations to our existing JPA/MongoDB data access objects (DAO). In fact, if you are using the same names it is not even necessary as they will be picked up automatically. Alternatively, if you want to separate the DAO from the GraphQL definition you can define a set of data transfer objects (DTO) and use those. This may give you more flexibility if you can’t change your DAO layer. We exposed the types to the GraphQL by adding a root query method to each service i.e.:

package io.committed.query;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;import io.committed.dao.repository.DemoRepository;import io.committed.dto.Document;import io.leangen.graphql.annotations.GraphQLQuery;@Componentpublic class DocumentService {  @Autowired  DemoRepository repository;  @GraphQLQuery(name = "allDocuments", description="Get all documents")  public List<Document> getDocuments() {    return repository.findAll();  }}

Arguments can be added to these methods for filtering, limiting, etc and if using Streams these can be returned directly:

@GraphQLQuery(name = "allDocuments", description="Get all documents")  public Stream<Document> getDocuments(      @GraphQLArgument(name = "limit", defaultValue = "0") int limit) {    Stream<Document> stream = repository.streamAll();    if (limit > 0) {      stream = stream.limit(limit);    }    return stream;  }

Similarly, we can get a specific document by id, and directly return anOptional:

@GraphQLQuery(name = "document")  public Optional<Document> getDocument(@GraphQLArgument(name = "id") String id) {    return repository.findById(id);  }

In GraphQL the client asks explicitly for what data the result should contain. This does not have to be restricted to the fields of your data objects, methods can also be used to provide calculated results, here is a trivial example:

package io.committed.dto;import io.leangen.graphql.annotations.GraphQLId;import io.leangen.graphql.annotations.GraphQLQuery;import lombok.Data;@Datapublic class Document {  @GraphQLId  private String id;  private String content;  @GraphQLQuery(name = "length")  public int length() {    return content.length();  }}

This will expose alength field on theDocument class. This method is only called if requested by the query so the client does not have to pay the penalty for any calculations that they do not need. Such methods also allow the client to save on data transfer by getting the server to do the calculations and only transferring the result.

Getting graphing

The real power of GraphQL comes from the ability to traverse data type by their joining properties. For example, if I have Entities extracted from a Document then I want to be able to query for the entities contained in a document. If these are already stored in your Document object this is trivial, however, they may be stored in a different table or collection in your database. To embed entities in the document we add the following:

@GraphQLQuery(name = "entities")  public Stream<Entity> getByDocument(@GraphQLContext Document document) {    return repository.getByDocumentId(document.getId());  }

where the@GraphQLContext annotation provides the linking logic to build the schema.

Getting querying

You can query using the GraphiQL UI hosted on/graphiql or send HTTP requests to/graphql and get the schema from/schema.json, I’m sure all these are configurable too. You can also use the GraphQL internally, for example by creating aQueryService:

package io.committed.query;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import graphql.ExecutionResult;import graphql.GraphQL;import graphql.schema.GraphQLSchema;@Servicepublic class QueryService {  private final GraphQL graphQL;  @Autowired  public QueryService(GraphQLSchema graphQLSchema) {    graphQL = GraphQL.newGraphQL(graphQLSchema).build();  }  public ExecutionResult query(String query) {    return graphQL.execute(query);  }}

Or by exposing theGraphQL object as a bean.

Getting better

We were able to get a quick GraphQL endpoint up and running in less that a day on our existing DAO objects providing a powerful querying mechanism for clients. During this investigation, we uncovered and reported a bug in graphql-spqr and got a rapid response from theauthor. It looks likely that this ecosystem will develop fast, out suggestions for improvements to graphql-spqr are:

  • Ability to ignore certain fields
  • Out of the box support for limiting and filtering
  • Support for graphql-java v5

Overall, this is a very promising route for rapid integration of GraphQL into an existing spring-boot server.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Location
    UK
  • Work
    Developer at Committed Software
  • Joined

More fromCommitted Software

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp