y0ngb1n

Aben Blog

欢迎来到我的技术小黑屋ヾ(◍°∇°◍)ノ゙
github

First Experience with GraphQL and Spring Boot

The project is hosted on GitHub: y0ngb1n/spring-boot-samples, feel free to Star, Fork 😘


GraphQL is both a query language for APIs and a runtime for fulfilling your data queries. GraphQL provides a complete description of the data in your API, allowing clients to request exactly the data they need, with no more and no less, making it easier for APIs to evolve over time and enabling powerful developer tools.

Define Schema#

# src/main/resources/schema.graphql
schema {
  query: Query
}

type Query {
  allBooks: [Book]
  book(id: String): Book
}

type Book {
  isbn: String
  title: String
  publisher: String
  authors: [String]
  publishedDate: String
}

Load and Parse the Defined Schema#

@Service
public class GraphQLService {

  @Value("classpath:schema.graphql")
  private Resource resource;

  @Getter
  private GraphQL graphQL;
  @Autowired
  private AllBooksDataFetcher allBooksDataFetcher;
  @Autowired
  private BookDataFetcher bookDataFetcher;

  @PostConstruct
  private void loadSchema() throws IOException {
    // Get the locally defined Schema file
    File schemaFile = resource.getFile();
    // Parse the Schema file
    TypeDefinitionRegistry typeRegistry = new SchemaParser().parse(schemaFile);
    RuntimeWiring wiring = buildRuntimeWiring();
    GraphQLSchema schema = new SchemaGenerator().makeExecutableSchema(typeRegistry, wiring);
    graphQL = GraphQL.newGraphQL(schema).build();
  }

  private RuntimeWiring buildRuntimeWiring() {
    return RuntimeWiring.newRuntimeWiring()
      .type("Query", typeWiring -> typeWiring
        .dataFetcher("allBooks", allBooksDataFetcher)
        .dataFetcher("book", bookDataFetcher)
      ).build();
  }
}

Provide DataFetcher#

Equivalent to providing the implementation of Query in the Schema:

type Query {
  allBooks: [Book]
  book(id: String): Book
}

AllBooksDataFetcher corresponds to the implementation of allBooks: [Book]:

@Component
public class AllBooksDataFetcher implements DataFetcher<List<Book>> {

  @Autowired
  private BookRepository bookRepository;

  @Override
  public List<Book> get(DataFetchingEnvironment dataFetchingEnvironment) {
    return bookRepository.findAll();
  }
}

BookDataFetcher corresponds to the implementation of book(id: String): Book:

@Component
public class BookDataFetcher implements DataFetcher<Book> {

  @Autowired
  private BookRepository bookRepository;

  @Override
  public Book get(DataFetchingEnvironment dataFetchingEnvironment) {
    String isn = dataFetchingEnvironment.getArgument("id");
    return bookRepository.findById(isn).orElse(null);
  }
}

Provide GraphQL API#

@RestController
@RequestMapping(path = "/v1/books")
public class BookController {

  @Autowired
  private GraphQLService graphQLService;

  @PostMapping
  public ResponseEntity<Object> getAllBooks(@RequestBody String query) {
    ExecutionResult execute = graphQLService.getGraphQL().execute(query);
    return new ResponseEntity<>(execute, HttpStatus.OK);
  }
}

Start and Test#

$ mvn install
...
[INFO] BUILD SUCCESS
...
$ mvn spring-boot:run
...
2019-08-24 19:35:11.700  INFO 14464 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-08-24 19:35:11.702  INFO 14464 --- [           main] i.g.y.s.graphql.GraphQLApplication       : Started GraphQLApplication in 16.808 seconds (JVM running for 25.601)

Query Partial Fields

$ curl -X POST \
  http://127.0.0.1:8080/v1/books \
  -H 'Content-Type: text/plain' \
  -d '{
    allBooks {
      isbn
      title
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   579    0   524  100    55  34933   3666 --:--:-- --:--:-- --:--:-- 38600
{
  "errors": [],
  "data": {
    "allBooks": [
      {
        "isbn": "9787111213826",
        "title": "Thinking in Java (4th Edition)"
      },
      ...
    ]
  },
  "extensions": null,
  "dataPresent": true
}
$ curl -X POST \
  http://127.0.0.1:8080/v1/books \
  -H 'Content-Type: text/plain' \
  -d '{
    book(id: "9787121362132") {
      title
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   210    0   159  100    51   1691    542 --:--:-- --:--:-- --:--:--  2234
{
  "errors": [],
  "data": {
    "book": {
      "title": "Highly Available and Scalable Microservice Architecture: Based on Dubbo, Spring Cloud, and Service Mesh"
    }
  },
  "extensions": null,
  "dataPresent": true
}

Query All Fields

$ curl -X POST \
  http://127.0.0.1:8080/v1/books \
  -H 'Content-Type: text/plain' \
  -d '{
    allBooks {
      isbn
      title
      authors
      publisher
      publishedDate
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1139    0  1044  100    95    750     68  0:00:01  0:00:01 --:--:--   818
{
  "errors": [],
  "data": {
    "allBooks": [
      {
        "isbn": "9787111213826",
        "title": "Thinking in Java (4th Edition)",
        "authors": [
          "Bruce Eckel"
        ],
        "publisher": "Mechanical Industry Press",
        "publishedDate": "2007-06-01"
      },
      ...
    ]
  },
  "extensions": null,
  "dataPresent": true
}
$ curl -X POST \
  http://127.0.0.1:8080/v1/books \
  -H 'Content-Type: text/plain' \
  -d '{
    book(id: "9787121362132") {
      title
      authors
      publisher
      publishedDate
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   421    0   320  100   101   312k    98k --:--:-- --:--:-- --:--:--  411k
{
  "errors": [],
  "data": {
    "book": {
      "title": "Highly Available and Scalable Microservice Architecture: Based on Dubbo, Spring Cloud, and Service Mesh",
      "authors": [
        "Cheng Chao",
        "Liang Guizhao",
        "Qin Jinwei",
        "Fang Zhibin",
        "Zhang Yi",
        "Du Qi",
        "Yin Qi",
        "Xiao Guanyu"
      ],
      "publisher": "Electronic Industry Press",
      "publishedDate": "2019-05-01"
    }
  },
  "extensions": null,
  "dataPresent": true
}

Query Multiple Data

$ curl -X POST \
  http://127.0.0.1:8080/v1/books \
  -H 'Content-Type: text/plain' \
  -d '{
    allBooks {
      isbn
      title
    }
    book(id: "9787121362132") {
      title
      authors
      publisher
      publishedDate
  }
}' | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   930    0   785  100   145   3866    714 --:--:-- --:--:-- --:--:--  4581
{
  "errors": [],
  "data": {
    "allBooks": [
      {
        "isbn": "9787111213826",
        "title": "Thinking in Java (4th Edition)"
      },
      {
        "isbn": "9787111421900",
        "title": "Understanding the Java Virtual Machine: Advanced Features and Best Practices (2nd Edition)"
      },
      {
        "isbn": "9787115221704",
        "title": "Refactoring: Improving the Design of Existing Code (2nd Edition)"
      },
      {
        "isbn": "9787121362132",
        "title": "Highly Available and Scalable Microservice Architecture: Based on Dubbo, Spring Cloud, and Service Mesh"
      },
      {
        "isbn": "9787302392644",
        "title": "The Mythical Man-Month (40th Anniversary Chinese Edition)"
      }
    ],
    "book": {
      "title": "Highly Available and Scalable Microservice Architecture: Based on Dubbo, Spring Cloud, and Service Mesh",
      "authors": [
        "Cheng Chao",
        "Liang Guizhao",
        "Qin Jinwei",
        "Fang Zhibin",
        "Zhang Yi",
        "Du Qi",
        "Yin Qi",
        "Xiao Guanyu"
      ],
      "publisher": "Electronic Industry Press",
      "publishedDate": "2019-05-01"
    }
  },
  "extensions": null,
  "dataPresent": true
}

As can be seen, the API remains unchanged while only the query content is modified, and it automatically responds with different results.


Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.