-
Notifications
You must be signed in to change notification settings - Fork 5
Maven GraphQL Schema Truncation
The main weakness of the Kobby plugin at the moment is the difficulty of working with giant GraphQL schemas. The schema can contain hundreds of types. And to work with these types, the Kobby plugin generates a huge number of classes. To compile these classes, Kotlin requires a lot of RAM and time. But the developer does not always need all the types in the GraphQL schema. Often he works with a small subset of types.
To simplify code generation in such cases, the Kobby plugin provides a mechanism for truncating the GraphQL schema. The truncation occurs in two stages:
- The first stage preserves all GraphQL fields that match the truncation query in the schema and removes all other fields.
- The second stage removes all GraphQL types from the schema that are not accessible from the schema root (Query, Mutation or Subscription types).
To write a schema truncation query, we use the GSEL query language, which allows us to search for fields in various GraphQL types based on a set of conditions.
To configure GraphQL schema truncation, use the truncate section in the schema section:
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<!-- GraphQL schema truncation configuration -->
<truncate>
<!-- Print detailed schema truncation report to console -->
<reportEnabled>false</reportEnabled>
<!-- Is Regex enabled in GraphQL schema truncation query -->
<!-- By default, a simplified Kobby Pattern is used. -->
<regexEnabled>false</regexEnabled>
<!-- Are patterns used in a GraphQL schema truncation query -->
<!-- case sensitive -->
<caseSensitive>true</caseSensitive>
<!-- A query used to truncate the GraphQL schema -->
<!-- before generating code -->
<queries>
<!-- Schema truncation query (GSEL) -->
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>A simple truncation configuration looks like this:
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<truncate>
<reportEnabled>true</reportEnabled>
<queries>
<query>
<type>__any</type>
<exclude>
<dependency>Film|Actor</dependency>
<subTypeDependency>Film|Actor</subTypeDependency>
</exclude>
</query>
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>With this configuration, we remove all fields of type Film and Actor from the GraphQL schema.
Let's look at some GraphQL schema truncation strategies with examples.
The most obvious strategy is to explicitly exclude unused fields from GraphQL types. But, surprisingly, this strategy is
the most labor-intensive and least efficient. Let's look at
the Cinema
schema from the example project. This schema allows you to work with three types - Country, Film and Actor. Let's
say I only need the Country from the schema. Let exclude fields that return Film and Actor.
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<truncate>
<reportEnabled>true</reportEnabled>
<queries>
<query>
<type>__query</type>
<exclude>
<field>film|films|actor|actors</field>
</exclude>
</query>
<query>
<type>__mutation</type>
<exclude>
<field>createFilm|createActor|updateBirthday</field>
</exclude>
</query>
<query>
<type>__subscription</type>
<exclude>
<field>filmCreated|actorCreated</field>
</exclude>
</query>
<query>
<type>Country</type>
<exclude>
<field>film|films|actor|actors</field>
</exclude>
</query>
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>We build the project (mvn clean compile) and see in the report that the fields we selected
were deleted, but the Film and Actor types were not deleted:
[kobby] GraphQL schema truncation enabled! (Kobby pattern case sensitive)
[kobby] Source schema weight: 15 (7 objects, 2 interfaces, 1 unions, 2 enums, 3 inputs).
[kobby] Detailed truncation report ****************************************************
Excluded inputs:
FilmInput
ActorInput
TagInput
Excluded object fields:
Query:
film
films
actor
actors
Mutation:
createFilm
createActor
updateBirthday
Subscription:
filmCreated
actorCreated
Country:
film
films
actor
actors
[kobby] *******************************************************************************
[kobby] GraphQL schema truncation completed. 3 GraphQL types excluded (3 inputs).
[kobby] Truncated schema weight: 12 (7 objects, 2 interfaces, 1 unions, 2 enums).
Why did this happen? The thing is that the types we are deleting are accessible not only through direct dependencies,
but also through hierarchical ones. Both Film and Actor types implement Taggable interface and are members of
Native union. And there are fields in the schema that return these abstract types. Thus, Film and Actor types are
implicitly accessible from the schema root. Let's exclude such fields too:
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<truncate>
<reportEnabled>true</reportEnabled>
<queries>
<query>
<type>__query</type>
<exclude>
<field>film|films|actor|actors|taggable</field>
</exclude>
</query>
<query>
<type>__mutation</type>
<exclude>
<field>createFilm|createActor|updateBirthday</field>
</exclude>
</query>
<query>
<type>__subscription</type>
<exclude>
<field>filmCreated|actorCreated</field>
</exclude>
</query>
<query>
<type>Country</type>
<exclude>
<field>film|films|actor|actors|taggable|native</field>
</exclude>
</query>
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>We rebuild the project and see in the final report that the Film and Actor types have been removed:
[kobby] GraphQL schema truncation enabled! (Kobby pattern case sensitive)
[kobby] Source schema weight: 15 (7 objects, 2 interfaces, 1 unions, 2 enums, 3 inputs).
[kobby] Detailed truncation report ****************************************************
Excluded scalars:
Date
Excluded objects:
Film
Actor
Tag
Excluded interfaces:
Taggable
Excluded unions:
Native
Excluded enums:
Genre
Gender
Excluded inputs:
FilmInput
ActorInput
TagInput
Excluded object fields:
Query:
film
films
actor
actors
taggable
Mutation:
createFilm
createActor
updateBirthday
Subscription:
filmCreated
actorCreated
Country:
film
films
actor
actors
taggable
native
[kobby] *******************************************************************************
To remove just two types, we had to write complex and cumbersome queries listing all the fields through which these
types are accessible. Is it possible to simply remove Film and Actor dependencies using GSEL? Of course we can!
Let's do it:
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<truncate>
<reportEnabled>true</reportEnabled>
<queries>
<query>
<type>__any</type>
<exclude>
<dependency>Film|Actor</dependency>
<subTypeDependency>Film|Actor</subTypeDependency>
</exclude>
</query>
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>- The
<dependency>Film|Actor</dependency>condition matches fields that return types that match theFilm|Actorpattern. - The
<subTypeDependency>Film|Actor</subTypeDependency>condition matches fields where one of the subtypes matches theFilm|Actorpattern.
Detailed truncation report:
[kobby] GraphQL schema truncation enabled! (Kobby pattern case sensitive)
[kobby] Source schema weight: 15 (7 objects, 2 interfaces, 1 unions, 2 enums, 3 inputs).
[kobby] Detailed truncation report ****************************************************
Excluded scalars:
Date
Excluded objects:
Film
Actor
Tag
Excluded interfaces:
Taggable
Excluded unions:
Native
Excluded enums:
Genre
Gender
Excluded inputs:
FilmInput
ActorInput
TagInput
Excluded object fields:
Query:
film
films
actor
actors
taggable
Mutation:
createFilm
createActor
updateBirthday
Subscription:
filmCreated
actorCreated
Country:
film
films
actor
actors
taggable
native
[kobby] *******************************************************************************
[kobby] GraphQL schema truncation completed.
[kobby] 10 GraphQL types excluded (3 objects, 1 interfaces, 1 unions, 2 enums, 3 inputs).
[kobby] Truncated schema weight: 5 (4 objects, 1 interfaces).
Okay, the strategy of excluding unused types looks good, but
our example schema
is too small. It consists of only 3 objects. But what happens if we try to truncate a really large GraphQL schema? Let's
take a look at the
official GitHub GraphQL schema.
It consists of 777 objects. Let's assume that we only need to work with 3 objects from this schema - User, Team and
Organization. Should we write a GSEL query where we list the remaining 774 objects that we need to exclude? Of course
not! Let's work only with those objects that we need to include in the resulting schema:
<?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/maven-v4_0_0.xsd">
<build>
<plugins>
<plugin>
<groupId>io.github.ermadmi78</groupId>
<artifactId>kobby-maven-plugin</artifactId>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>generate-kotlin</goal>
</goals>
</execution>
</executions>
<configuration>
<schema>
<truncate>
<queries>
<query>
<type>__any</type>
<include>
<dependency>
__anyScalar|__anyEnum|User|Team|Organization
</dependency>
</include>
</query>
<query>
<type>__mutation</type>
<include>
<argumentDependency>
*User*Input*|*Team*Input*|*Organization*Input*
</argumentDependency>
</include>
</query>
</queries>
</truncate>
</schema>
</configuration>
</plugin>
</plugins>
</build>
</project>- The
<dependency>__anyScalar|__anyEnum|User|Team|Organization</dependency>condition matches fields of scalar and enum types, as well as theUser,Team, andOrganizationtypes. - The
<argumentDependency>*User*Input*|*Team*Input*|*Organization*Input*</argumentDependency>condition matches fields where one of the argument types matches the*User*Input*pattern.
We use the argumentDependency condition to preserve fields in the Mutation, which takes input objects for User,
Team, and Organization as arguments.
Truncation result:
[kobby] GraphQL schema truncation enabled! (Kobby pattern case sensitive)
[kobby] Source schema weight: 1313 (777 objects, 45 interfaces, 37 unions, 189 enums, 265 inputs).
[kobby] GraphQL schema truncation completed.
[kobby] 1219 GraphQL types excluded (748 objects, 30 interfaces, 21 unions, 178 enums, 242 inputs).
[kobby] Truncated schema weight: 94 (29 objects, 15 interfaces, 16 unions, 11 enums, 23 inputs).