1.What is Graphql
GraphQL is a query language for APIs, a server-side runtime that uses a type system to execute queries (the type system is defined by your data). GraphQL is not tied to any specific database or storage engine, but relies on your existing code and data support.
advantage
- GraphQL is fast and relatively stable. GraphQL operates at the data level, so it is relatively fast.
- GraphQL can obtain more resources. When querying a data, not only this data, but also another data referenced by the data can be quickly queried. GraphQL can obtain as much data as possible in a single request, and GraphQL still performs well under weak network conditions.
- GraphQL is a single endpoint query, and all queries are completed in this endpoint.
The sustainability of GraphQL is very good. Whether it is a new field or an old field, it can handle it well and its maintainability is also excellent. - GraphQL has the feature of backward compatibility. Even if it is a function from a long time ago, GraphQL is still very compatible with it, ensuring the normal operation of the old version without affecting the addition of new functions and the overall stability. The advantage of this is that you don’t need to worry about version numbers.
- GraphQL has strong types. In GraphQL queries, one level corresponds to a strong type, and this type serves as a description of a field. The advantage of this is that errors can be checked and prompted before querying, making it easier to locate problems and improve performance.
- Introspection: You can query the types supported by the GraphQL server. This creates a powerful platform for tooling and client software to build on this information for code generation in statically typed languages, our application frameworks, IDEs such as Relay or GraphiQL.
- GraphQL allows users to determine the types supported by the server. The advantage of this is that it has established a relatively mature and powerful application platform for many tools or terminals that use GraphQL. Through this platform, some frameworks and tools are continuously optimized and improved.
disadvantage
- GraphQL cannot complete deep queries, so it cannot perform one-time queries on data of unknown depth.
- GraphQL has a very rigid response structure, and you have to follow this structure to query the data, or add a converter to convert it yourself.
- GraphQL cannot do network-level caching, so you must use another method for persistent queries.
- GraphQL does not have the function of uploading files by default, and GraphQL does not accept file type parameters, but you can use REST to upload files to achieve the purpose of uploading files.
GraphQL execution is unpredictable because GraphQL is too flexible. - For the same simple API, GraphQL will appear very complex, so it is recommended that simple APIs use RSET.
2.mysql environment setup
Refer to the mysql module in the code repository. Only docker-compose.yml is posted here.
version: '3'
services:
mysql:
image: registry.cn-hangzhou.aliyuncs.com/zhengqing/mysql:5.7
container_name: mysql_3306
restart: unless-stopped
volumes:
- "./mysql/my.cnf:/etc/mysql/my.cnf"
- "./mysql/init-file.sql:/etc/mysql/init-file.sql"
- "./mysql/data:/var/lib/mysql"
# - "./mysql/conf.d:/etc/mysql/conf.d"
- "./mysql/log/mysql/error.log:/var/log/mysql/error.log"
- "./mysql/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d" # init sql script directory -- tips: it can be excute when `/var/lib/mysql` is empty
environment: # set environment,equals docker run -e
TZ: Asia/Shanghai
LANG: en_US.UTF-8
MYSQL_ROOT_PASSWORD: root # set root password
MYSQL_DATABASE: demo # init database name
ports: # port mappping
- "3306:3306"
start
docker-compose -f docker-compose.yml -p mysql5.7 up -d
init scripts
CREATE DATABASE IF NOT EXISTS `BOOK_API_DATA`;
USE `BOOK_API_DATA`;
CREATE TABLE IF NOT EXISTS `Book` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`pageCount` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Index_name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=235 DEFAULT CHARSET=utf8;
CREATE TABLE `Author` (
`id` INT(20) NOT NULL AUTO_INCREMENT,
`firstName` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`lastName` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_general_ci',
`bookId` INT(20) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `Index_name` (`firstName`) USING BTREE,
INDEX `FK_Author_Book` (`bookId`) USING BTREE,
CONSTRAINT `FK_Author_Book` FOREIGN KEY (`bookId`) REFERENCES `BOOK_API_DATA`.`Book` (`id`) ON UPDATE CASCADE ON DELETE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
AUTO_INCREMENT=6
;
INSERT INTO `Book` (`id`, `name`, `pageCount`) VALUES (1, 'the golden ticket', '255');
INSERT INTO `Book` (`id`, `name`, `pageCount`) VALUES (2, 'coding game', '300');
INSERT INTO `Author` (`id`, `firstName`, `LastName`, `bookId`) VALUES (4, 'Brendon', 'Bouchard', 1);
INSERT INTO `Author` (`id`, `firstName`, `LastName`, `bookId`) VALUES (5, 'John', 'Doe', 2);
3.Code Project
experiment purpose
implement an example base on the graphql
implementation process
1. Define Schema. Schema is defined using GraphQL Schema Definition Language (SDL)
2. Implement Resolver. The Resolver function is responsible for obtaining the requested data from the data source.
3. Configure and start the GraphQL server. To start the GraphQL server, you need to install the corresponding dependencies and configure the server.
pomxml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>GraphQL</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<kotlin.version>1.5.0</kotlin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-spring-boot-starter</artifactId>
<version>12.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.graphql-java-kickstart</groupId>
<artifactId>graphql-java-tools</artifactId>
<version>12.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>26.0-jre</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
GraphQLQueryResolver
package com.et.graphql.queryresolvers;
import com.et.graphql.model.Author;
import com.et.graphql.model.Book;
import com.et.graphql.repository.AuthorRepository;
import com.et.graphql.repository.BookRepository;
import graphql.kickstart.tools.GraphQLQueryResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BookQuery implements GraphQLQueryResolver{
@Autowired
BookRepository bookRepository;
@Autowired
AuthorRepository authorRepository;
public Iterable<Book> allBook(){
return bookRepository.findAll();
}
public Book getBookByName(String name){
return bookRepository.findBookByName(name);
}
public Iterable<Author> allAuthor(){
return authorRepository.findAll();
}
}
package com.et.graphql.queryresolvers;
import com.et.graphql.model.Book;
import com.et.graphql.repository.BookRepository;
import graphql.kickstart.tools.GraphQLMutationResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
@Component
public class BookMutation implements GraphQLMutationResolver {
@Autowired
BookRepository bookRepository;
public Book newBook(String name, String pageCount){
Book book = new Book();
book.setName(name);
book.setPageCount(pageCount);
return bookRepository.save(book);
}
public Book deleteBook(Integer id){
Book deleteBook = new Book();
Optional<Book> findBook = bookRepository.findById(id);
if(findBook.isPresent()){
bookRepository.delete(findBook.get());
deleteBook = findBook.get();
}
return deleteBook;
}
}
package com.et.graphql.queryresolvers;
import com.et.graphql.model.Author;
import com.et.graphql.model.Book;
import com.et.graphql.repository.AuthorRepository;
import graphql.kickstart.tools.GraphQLResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class BookAuthorResolver implements GraphQLResolver<Book> {
@Autowired
AuthorRepository authorRepository;
public Author getAuthor(Book book){
return authorRepository.findAuthorByBookId(book.getId());
}
}
graphqls(/resources/graphql)
type Book {
id: Int
name: String
pageCount: String
author: Author
}
type Query {
allBook: [Book]
allAuthor:[Author]
getBookByName(name: String): Book
}
type Mutation {
newBook(name: String!, pageCount: String): Book
deleteBook(id:Int!):Book
}
type Author {
id: Int
firstName: String
lastName: String
bookId: Int
}
model
package com.et.graphql.model;
import javax.persistence.*;
@Entity
@Table(name = "Author", schema = "BOOK_API_DATA")
public class Author {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Integer id;
@Column(name = "firstname")
String firstName;
@Column(name = "lastname")
String lastName;
@Column(name = "bookid")
Integer bookId;
public Author(Integer id, String firstName, String lastName, Integer bookId) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.bookId = bookId;
}
public Author() {
}
public Integer getId() {
return id;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public void setId(Integer id) {
this.id = id;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getBookId() {
return bookId;
}
public void setBookId(Integer bookId) {
this.bookId = bookId;
}
}
package com.et.graphql.model;
import javax.persistence.*;
@Entity
@Table(name = "Book", schema = "BOOK_API_DATA")
public class Book {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
@Column(name = "pagecount")
private String pageCount;
public Book(Integer id, String name, String pageCount) {
this.id = id;
this.name = name;
this.pageCount = pageCount;
}
public Book() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPageCount() {
return pageCount;
}
public void setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
repository
package com.et.graphql.repository;
import com.et.graphql.model.Author;
import org.springframework.data.repository.CrudRepository;
public interface AuthorRepository extends CrudRepository<Author, Integer> {
Author findAuthorByBookId(Integer bookId);
}
package com.et.graphql.repository;
import com.et.graphql.model.Book;
import org.springframework.data.repository.CrudRepository;
public interface BookRepository extends CrudRepository<Book, Integer> {
Book findBookByName(String name);
}
DemoApplication.java
package com.et.graphql;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan(basePackages = "com.et.graphql.queryresolvers")
public class BookAPIApplication {
public static void main(String[] args) {
SpringApplication.run(BookAPIApplication.class, args);
}
}
application.yaml
spring.jpa.hibernate.ddl-auto=none
spring.jpa.database=mysql
spring.jpa.open-in-view=true
spring.jpa.show-sql=true
server.port=8088
#logging.level.org.hibernate=DEBUG
logging.level.org.hibernate.SQL=DEBUG
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.hibernate.use-new-id-generator-mappings= false
# book api db"
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
above it’s just some key codes ,for all codes ,you can code reponsitory below.
Code Reponsitory
4.Test
start spring boot application ,open the postman,input
http://127.0.0.1:8088/graphql
query {
allBook{
id
name
pageCount
}
}
response