graphqlgraphql-javagraphql-spqrgraphql-spring-boot

Why does graphql java query all fields in entity when I only ask for a few?


I created a basic graphql-java app with the spring boot starter and using the graphql spqr library against an MSSQL database utilizing Hibernate and Jpa.

I have an entity called "Task" with 5 fields. I have a simple Jpa repository and a simple Jpa service that calls a "findAllTasks" method. It works great, but if I specify, for example, only one field to query with graphiql, I can see through my SQL log that the select command executed is querying for ALL fields in my Task entity/table, rather than the one I want. Is this expected? I thought graphql only selects the fields you specify in the query command?

Here is my code:

Entity

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Task {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long id;

    @Column
    public String desc;

    @Column
    public LocalDateTime createdOn;

    @Column
    public LocalDateTime modifiedOn;

    @Column
    public String owner;
}

Repository

@Repository
public interface TaskRepository extends JpaRepository<Task, Long> {}

Service

@GraphQLApi
@Service
public class TaskService {
    private TaskRepository taskRepo;

    @Autowired
    public TaskService(TaskRepository taskRepo) {
        this.taskRepo = taskRepo;
    }

    @GraphQLQuery
    public List<Task> findAllTasks() {
        return taskRepo.findAll();
    }
}

When I run the following in graphiql:

query {
    findAllTasks {
        id
    }
}

I get the following SQL statement that was generated from my log:

select task0_.id as Task1_1_0_. task0_.desc as Task1_2_0, task0_.createdOn as Task1_3_0, task0_.modifiedOn as Task1_4_0, task0_.owner as Task1_4_0 from Task as task0_


Solution

  • You have to make a distinction between your GraphQL API and your database. You defined a query method GraphQL that is called findAllTasks. In consequence, when you call this GraphQL query with any number of fields, it will call the Java method implementation findAllTasks.

    You can see that the implementation of this Java method calls taskRepo.findAll(). Therefore, you will fetch all data from your tasks in database.

    GraphQL will then filter the data from the tasks fetched by your Java method to match what is asked in the GraphQL query.

    In a nutshell, GraphQL is in charge in returning just the fields that you requested, but your implementation is in charge of getting the data from the database.

    Disclaimer: I'm not an expert of graphql-spqr, so the upcoming information might not work in your case (as it applied to graphql-java).

    If you feel that your implementation is however not efficient enough (here we are really talking about efficiency), you could look into dataloaders.