Kotlin Spring Boot & GraphQL

What is the GraphQL?

Kotlin Spring Boot & GraphQL

What is the GraphQL?

GraphQL is a query language for APIs and is similar to REST. GraphQL is developed by Facebook and is open source. GraphQL uses a single endpoint for receiving requests. You have to write your controller name to your query. And also you can select specific fields for your response. Your response will be in JSON format.

There are three basic operations of GraphQL (like GET, POST, PUT…)

  • Query
  • Mutation
  • Subscriptions

Query

If you want to get something, you can use “query”.

Mutation

If you want to mutate/change/update your data or create a new one, you can use “mutation”.

Subscription

“Subscription” can be used for real-time operations. This operation usually implementing with WebSockets.

GraphQL Scheme

Schemas include your models, queries, mutations and etc. You have to define all related things in your .graphqls file. For instance, you can define a model using type keyword.

Some other keywords:

  • input : input parameter models
  • enum
  • scalar : for custom types

*For more information check the resources

Example GraphQL Scheme ( .graphqls file )

scalar DateTime 
 
type Query { 
    getAllUsers : [UserDTO] 
    getByID(id: ID!) : UserDTO 
} 
 
type Mutation { 
    createUser(user: UserCreateRequest): UserDTO 
    updateUser(user: UserUpdateRequest): UserDTO 
    deleteUser(id: ID!): Boolean 
} 
 
type UserDTO { 
    id: ID 
    username: String 
    createdAt: DateTime 
    updatedAt: DateTime 
    email: String 
    name: String 
    surname: String 
    role: Role 
} 
 
enum Role { 
    ADMIN 
    USER 
} 
 
input UserUpdateRequest{ 
    id:ID! 
    username: String! 
    email: String! 
    name: String 
    surname: String 
    role: Role 
} 
 
input UserCreateRequest{ 
    username: String! 
    email: String! 
    name: String 
    surname: String 
    role: Role 
}

Pros and Cons of GraphQL

Pros

  • Single endpoint
  • Fetch specific fields from data (Reduce response size)

Cons

  • Complex queries
  • Caching implementation

Testing — Graphiql

You can use Graphiql console for execute queries.

*In spring boot, you have to enable it before:

  • spring.graphql.graphiql.enabled=true

Testing — Postman

Select POST request and send your query in graphql section.

Spring Boot Kotlin implementation

Add these dependencies to your pom.xml file:

<dependency> 
            <groupId>org.springframework.graphql</groupId> 
            <artifactId>spring-graphql-test</artifactId> 
            <scope>test</scope> 
        </dependency> 
         
        <dependency> 
            <groupId>com.graphql-java</groupId> 
            <artifactId>graphql-java-extended-scalars</artifactId> 
            <version>19.0</version> 
        </dependency> 
 
         <dependency> 
            <groupId>org.springframework.boot</groupId> 
            <artifactId>spring-boot-starter-graphql</artifactId> 
        </dependency>

Controller

*Must be the same name with query and mutation definitions in .graphqls file

@Controller 
class UserController(private val userService: UserService) { 
 
    @QueryMapping 
    fun getAllUsers() = userService.getAllUsers().map { it.toDTO() } 
 
    @QueryMapping 
    fun getByID(@Argument id: Long)  
                      = userService.getUserByID(id).toDTO() 
 
    @MutationMapping 
    fun updateUser(@Argument user: UserUpdateRequest) 
                     = userService.updateUser(user).toDTO() 
 
    @MutationMapping 
    fun createUser(@Argument user: UserCreateRequest)  
                     = userService.createUser(user).toDTO() 
 
    @MutationMapping 
    fun deleteUser(@Argument id: Long)  
                     = userService.deleteUser(id) 
}
type Query { 
    getAllUsers : [UserDTO] 
    getByID(id: ID!) : UserDTO 
} 
 
type Mutation { 
    createUser(user: UserCreateRequest): UserDTO 
    updateUser(user: UserUpdateRequest): UserDTO 
    deleteUser(id: ID!): Boolean 
}

Error Handling

@Component 
class GlobalExceptionHandler : DataFetcherExceptionResolverAdapter() { 
 
 
    override fun resolveToSingleError(e: Throwable, 
                   env: DataFetchingEnvironment): GraphQLError? { 
        return when (e) { 
            is UserNotFoundException -> toGraphQLError(e) 
            is Exception -> toGraphQLError(e) 
            else -> super.resolveToSingleError(e, env) 
        } 
    } 
 
    private fun toGraphQLError(e: Throwable): GraphQLError? { 
        return GraphqlErrorBuilder.newError() 
              .message(e.message) 
              .errorType(ErrorType.DataFetchingException).build() 
    } 
}

Tests

/ /other annotations 
@AutoConfigureGraphQlTester 
internal class UserControllerTest( 
    @Autowired private val graphQlTester: GraphQlTester 
) { 
 
    @Test 
    fun `should return all users`() { 
        val query: String = """ 
       Query{ getAllUsers { id username email role name surname createdAt updatedAt } } 
     """ 
        graphQlTester.document(query) 
            .execute() 
            .path("getAllUsers") 
            .entityList(UserDTO::class.java) 
            .hasSize(2) 
    } 
}

Resources:

Repository:

  • kotlin:
GitHub - gurkanucar/spring-boot-kotlin-graphql: GraphQL example using kotlin and spring boot
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…
  • java example:
GitHub - folksdev/spring-boot-graphql
You can't perform that action at this time. You signed in with another tab or window. You signed out in another tab or…

Subscribe to gurkanucar

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe