GraphQL with Spring Boot and Kotlin

1. Introduction

2. Imports

implementation("org.springframework.boot:spring-boot-starter-web")
implementation("com.graphql-java:graphql-spring-boot-starter:5.0.2")
implementation("com.graphql-java:graphiql-spring-boot-starter:5.0.2")
implementation("com.graphql-java:graphql-java-tools:5.2.4")

3. Create Models

class Company(
val id: Long,
val name: String,
val address: String,
val zipCode: String
)
class Employee(
val id: Long,
val firstName: String,
val lastName: String,
val status: EmployeeStatus,
val company: Company
)

enum class EmployeeStatus {
ACTIVE, RETIRED
}

4. Create Repositories

4.1. Implement CompanyRepository

@Component
class CompanyRepository {

private val companyId = AtomicLong(4)

private val companies = mutableSetOf(
Company(1, "Company One", "Address 1", "10001"),
Company(2, "Company Two", "Address 2", "10002"),
Company(3, "Company Three", "Address 3", "10003"),
Company(4, "Company Four", "Address 4", "10004")
)
}
fun findAll(): Set = companies

fun findById(companyId: Long): Company =
companies.find { it.id == companyId }
?: throw RuntimeException("Company with id [$companyId] could not be found.")

fun create(name: String, address: String, zipCode: String): Company {
val company = Company(
id = companyId.incrementAndGet(),
name = name,
address = address,
zipCode = zipCode
)

companies.add(company)
return company
}

fun delete(id: Long): Boolean =
companies.removeIf { it.id == id }

4.2. Implement EmployeeRepository

@Component
class EmployeeRepository(
private val companyRepository: CompanyRepository
) {

val employerId = AtomicLong(3)

val employees = mutableSetOf(
Employee(1, "John", "Doe", EmployeeStatus.ACTIVE, companyRepository.findById(1)),
Employee(2, "Adam", "Nowak", EmployeeStatus.ACTIVE, companyRepository.findById(2)),
Employee(3, "Stan", "Bar", EmployeeStatus.RETIRED, companyRepository.findById(3))
)
}
fun findAll(): Set = employees

fun findById(employeeId: Long) =
employees.find { it.id == employeeId }
?: throw RuntimeException("Employee with id [$employeeId] could not be found.")

fun create(
firstName: String,
lastName: String,
status: EmployeeStatus,
companyId: Long
): Employee {
val company = companyRepository.findById(companyId)

val employee = Employee(
id = employerId.incrementAndGet(),
firstName = firstName,
lastName = lastName,
status = status,
company = company
)

employees.add(employee)
return employee
}

fun delete(id: Long): Boolean =
employees.removeIf { it.id == id }

5. Define GraphQL Schema

5.1. Describe Company Schema

type Company {
id: ID!
name: String!
address: String!
zipCode: String!
}

type Query {
companies: [Company]
companyById(id: ID!) : Company
}

type Mutation {
newCompany(name: String!, address: String!, zipCode: String!) : Company!
deleteCompany(id: ID!) : Boolean
}

5.2. Describe Employee Schema

type Employee {
id: ID!
firstName: String!
lastName: String!
status: EmployeeStatus!
company: Company!
}

enum EmployeeStatus{
ACTIVE, RETIRED
}

extend type Query {
employees: [Employee]
employeeById(id: ID!) : Employee
}

extend type Mutation {
newEmployee(firstName: String!, lastName: String!, status: EmployeeStatus!, companyId: ID!) : Employee!
deleteEmployee(id: ID!) : Boolean
}

6. Create Queries Resolvers

@Component
class CompanyQuery(
private val companyRepository: CompanyRepository
) : GraphQLQueryResolver {

fun companies(): Set =
companyRepository.findAll()

fun companyById(id: Long): Company =
companyRepository.findById(id)
}
@Component
class EmployeeQuery(
private val employeeRepository: EmployeeRepository
) : GraphQLQueryResolver {

fun employees(): Set =
employeeRepository.findAll()

fun employeeById(id: Long): Employee =
employeeRepository.findById(id)
}

7. Implement Mutations Resolvers

@Component
class CompanyMutation(
private val companyRepository: CompanyRepository
) : GraphQLMutationResolver {

fun newCompany(name: String, address: String, zipCode: String): Company =
companyRepository.create(name, address, zipCode)

fun deleteCompany(id: Long): Boolean =
companyRepository.delete(id)
}
@Component
class EmployeeMutation(
private val employeeRepository: EmployeeRepository
) : GraphQLMutationResolver {

fun newEmployee(
firstName: String,
lastName: String,
status: EmployeeStatus,
companyId: Long
): Employee =
employeeRepository.create(firstName, lastName, status, companyId)

fun deleteEmployee(id: Long): Boolean =
employeeRepository.delete(id)

}

8. Testing

8.1. Test Queries

query {
employees {
id
firstName
lastName
status
company {
name
}
}
}
{
"data": {
"employees": [
{
"id": "1",
"firstName": "John",
"lastName": "Doe",
"status": "ACTIVE",
"company": {
"name": "Company One"
}
}
...
query {
employeeById(id: 1) {
id
firstName
lastName
status
company {
id
name
}
}
}

# Result:

{
"data": {
"employeeById": {
"id": "1",
"firstName": "John",
"lastName": "Doe",
"status": "ACTIVE",
"company": {
"id": "1",
"name": "Company One"
}
}
}
}
query {
companies {
id
name
address
zipCode
}
}

# Result:

{
"data": {
"companies": [
{
"id": "1",
"name": "Company One",
"address": "Address 1",
"zipCode": "10001"
},
...

8.1. Test Mutations

mutation {
newCompany(name: "New", address: "Address new", zipCode: "10201") {
id
name
address
zipCode
}
}
{
"data": {
"newCompany": {
"id": "5",
"name": "New",
"address": "Address new",
"zipCode": "10201"
}
}
}
mutation {
newEmployee(firstName: "Piotr", lastName:"Wolak", status: ACTIVE, companyId: 2) {
id
firstName
lastName
status
company {
id
name
}
}
}

# Result:

{
"data": {
"newEmployee": {
"id": "4",
"firstName": "Piotr",
"lastName": "Wolak",
"status": "ACTIVE",
"company": {
"id": "2",
"name": "Company Two"
}
}
}
}
{
"data": {
"deleteCompany": true
}
}

# Result:

{
"data": {
"deleteCompany": true
}
}
mutation {
deleteEmployee(id: 1)
}

# Result:

{
"data": {
"deleteEmployee": true
}
}

9. Conclusion

Hi, my name is Piotr and I am the founder of Codersee- a technical blog, where I am teaching programming by practical step by step tutorials.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store