With a slew of benefits, GraphQL also introduces its own set of hurdles. With best practices yet to be discovered for many use-cases, careful consideration upfront is imperative. This talk aims to highlight issues less obvious at the beginning of a GraphQL-enabled project, with special focus on dealing with development and maintenance of a GraphQL schema. An approach leveraging dynamic schema generation is proposed in attempt to lower the effort needed to expose new or existing Java services while keeping the schema at all times in sync with the changes.
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Developing and maintaining a Java GraphQL back-end: The less obvious - Bojan Tomic - Codemotion Amsterdam 2017
1. Java & GraphQL: The less obvious
Bojan Tomić
AMSTERDAM 16 - 17 MAY 2017
2.
3. What?
● Server-side runtime for executing queries
● Type system
● Storage / language independent (think REST)
● Open source spec (tnx Facebook!)
(think WSDL/SOAP)
● Unrelated to graph DBs and their query languages
(Cypher, Gremlin etc)
● Data description + query language
4. Why?
Describe data Predictable resultsNo under/over-fetch
type Query {
hero (episode: Int): Character
}
{
hero (episode: 4) {
name
homeWorld {
name
type
}
}
}
{
"data" : {
"hero" : {
"name" : "Luke Skywalker"
"homeWorld" : {
"name" : "Tatooine"
"type" : "desert"
}
}
}
type Character {
name: String
friends: [Character]
homeWorld: Planet
}
type Planet {
name: String
type: String
}
15. The problem: Malicious queries
o Arbitrarily complex query
o Arbitrary size of the result
o Analyze AST complexity
o Limit depth
o Limit execution time
o Whitelist queries
16. The problem: N + 1
{
peopleByName (firstName : "John") {
firstName
lastName
twitterProfile {
handle
numberOfTweets
}
}
}
public class PersonService {
@GraphQLQuery(name = "twitterProfile")
public TwitterProfile getTwitterProfile (
Person person) {
return twitterApi.getProfile(person);
}
@Batched
List<
List<
>
>
17. The problem: Optimize fetching
{
peopleByName (name: "John") {
firstName
lastName
}
}
@GraphQLQuery(name = "peopleByName")
public List<Person> getPeopleByName(String name) {
SELECT * FROM Users WHERE name = ‘John’;
return …;
}
18. The problem: Optimize fetching
{
peopleByName (name: "John") {
firstName
lastName
}
}
@GraphQLQuery(name = "peopleByName")
public List<Person> getPeopleByName(String name,
@GraphQLEnvironment List<String> subFields) {
SELECT firstName, lastName FROM Users
WHERE name = ‘John’;
return …;
}
19. The problem: Authorization
o Inject security context into the
resolver
@RequestMapping(value="/graphql")
public Object graphql(@RequestBody Map<String, Object> request) {
String query = request.get("query").toString();
User user = SecurityContextHolder.getContext().getAuthentication();
}
public String getProfile(..., @GraphQLRootContext User user) {
if (current.getId() == ...) {
return ...
}
}
ExecutionResult executionResult = graphQL.execute(query, user);