Graphql
Interview
It's not only a frame ,but also a thinking. It's very strong difference with traditional frame like SpringMvc of 3 layers(Repo,Service,EndPoint).
It can make staffs' communication of frontend and backend more erasy and fast.
We don't need to define interface. Graphql give us a GUI to let frontend to view and test. However this's not only reason we're using it. We can use name to define interface of finding like hibernate(findStudentById,findStudentByName).
Core Thinking
Graphql has 3 core part of .java file and some configs.
.graphqls
This's config file of Graphql. It's mainly divided into 2 part.
root.graphqls : We will define interface in there. Include find,update,insert,delect.
# "Query" represent belows are Query statement.
type Query{
findStudentById(id:Int!): Student
# "!" represent id is Required fields.
# Student is we define a class.
# When you visit this interface with "id", frontend will get a json.
}
# "Mutation" represent belows are Modify statement.
type Mutation {
insert(teacher : TeacherInput!) : Teacher
# TeacherInput is we define a class for Input data.
# Teacher is we define a class.
}
schama.graphqls : We will define Model for receive or return Input or Output data.
type Student{
id : Int!
# "!" represent id is Required fields.
name : String
course : [Course]
#"[]" represent this fields is a list.
}
# every fields must both a scalar.
type Teacher{
id : Int!
name : String
course : [Course]
}
type Course{
id : Int!
name :String
teacher : Teacher
student : [Student]
}
# input type is used for receiving.
input TeacherInput{
id : Int!
name : String
}
What is "Scalar"
Graphql will return a json. Every layer of this json will both be analysised. So we must provide a type Graphql can know like int,long,string,boolean etc. Of coures you can define Scalar by yourself.But we can't make ervery type both defined scalar. So we need Resolver.
Resolver
It's a Serious java file. When apearing not scalar in our type, we need use Resolver to resolve it.
@Component
public class TeacherResolver implements GraphQLResolver<Teacher> {
@Autowired
CourseDao courseDao;
public List<Course> getCourse(Teacher teacher){
return courseDao.findCourseByTeacherId(teacher.getId());
}
}
This's a Resolver of Teacher.
It implement a class of GraphQLResolver. And we write a method "getCourse".
We can find "Course" in the schema.graphqls. So we must use this name of method. Parameter and return value must Corresponding to it. Parameter of Teacher's Resolver must be Teacher.
@Component
public class StudentResolver implements GraphQLResolver<Student> {
@Autowired
StudentCourseDao studentCourseDao;
@Autowired
CourseDao courseDao;
public List<Course> getCourse(Student student){
List<Course> courseList = new ArrayList<>();
List<StudentCourse> studentCourseList = studentCourseDao.findStudentCourseByStudentId(student.getId());
for (StudentCourse studentCourse :
studentCourseList) {
courseList.add(courseDao.findCourseById(studentCourse.getCourseId()));
}
return courseList;
}
}
This is a Resolver of Student. It's more Complex.
Because Student and Course is many to many relationship. We can use a middle value like StudentCourse.
@Component
public class StudentResolver implements GraphQLResolver<Student> {
@Autowired
StudentCourseDao studentCourseDao;
@Autowired
CourseDao courseDao;
public List<StudentCourse> getStudentCourse(Student student){
return studentCourseDao.findStudentCourseByStudentId(student.getId());
}
public List<Course> getCourse(List<StudentCourse> studentCourses){
List<Course> courseList = new ArrayList<>();
for (StudentCourse studentCourse :
studentCourses) {
courseList.add(courseDao.findCourseById(studentCourse.getCourseId()));
}
return courseList;
}
}
This's not allowed. It violates the above principle.
Query and Mutation
In the standard, Query(Mutation) and Resolver is one Layer. But I don't tink so. Theri work is totally different. Query file will finish implement interface. But their return value need be packaged by Resolver. This return value will return to frontend by json. We need only get data from database.
@Component
public class Query implements GraphQLQueryResolver {
@Autowired
StudentDao studentDao;
@Autowired
TeacherDao teacherDao;
@Autowired
CourseDao courseDao;
public Student findStudentById(Integer id){
return studentDao.findStudentById(id);
}
}
@Component
public class Mutation implements GraphQLMutationResolver {
@Autowired
StudentDao studentDao;
@Autowired
TeacherDao teacherDao;
@Autowired
CourseDao courseDao;
public Teacher insert(TeacherInput teacher){
//Input data need use Input Type.
Teacher teacher1 = new Teacher(teacher.getId(),teacher.getName());
return teacherDao.insertTeacher(teacher1);
}
}
So easey.
Test
It's said above Graphql provide a GUI to test.
We need start project, and visit "/graphiql"
We can find a document in the right. You can find defined of interface.
In the left we can use statement to request interface.
{
findStudentById(id: 1) {
name,
id,
course {
id,
teacher{
name
}
name
}
}
}
We must write what we need fields.
{
"data": {
"findStudentById": {
"name": "Student1",
"id": 1,
"course": [
{
"id": 2,
"teacher": {
"name": "teacher3"
},
"name": "Course2"
},
{
"id": 3,
"teacher": {
"name": "teacher4"
},
"name": "Course3"
}
]
}
}
}
This's json of return value. Frontend can use them directly.