Skip to content

Commit

Permalink
Use spring-graphql (#140)
Browse files Browse the repository at this point in the history
  • Loading branch information
Robert Wiesner authored Dec 4, 2022
1 parent 188b8fa commit 04e29e4
Show file tree
Hide file tree
Showing 14 changed files with 91 additions and 73 deletions.
5 changes: 5 additions & 0 deletions .graphqlconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Spring GraphQL Schema",
"schemaPath": "src/main/resources/graphql/schema.graphqls",
"extensions": {}
}
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ Simple Spring WebFlux Project (see [Help.md](HELP.md)) with:

* Classic Annotation Based REST
* WebFlux.Fn / coRouter REST
* [graphql-kotlin](https://github.com/ExpediaGroup/graphql-kotlin) GraphQL ([Why?](https://opensource.expediagroup.com/graphql-kotlin/docs/framework-comparison))
- Moved from [graphql-kotlin](https://github.com/ExpediaGroup/graphql-kotlin) to [spring-graphql](https://docs.spring.io/spring-graphql/docs/current/reference/html)
- For [graphql-kotlin](https://opensource.expediagroup.com/graphql-kotlin/docs/framework-comparison) impl. with Spring Boot 2.x.x use [#811dcc2](https://github.com/rowi1de/graphql-reactive/commit/c88c63b40584c5e0ef3d64d6ee4a108bd5608aa1)

## Kotlin

Expand All @@ -25,26 +26,26 @@ This project uses [ktlint](https://ktlint.github.io/)
### Graphql
* graphql Endpoints
* [graphql](http://localhost:8082/graphql)
* [playground](http://localhost:8082/playground)
* [sdl](http://localhost:8082/sdl)
* [subscription](http://localhost:8082/subscription)
* [graphiql](http://localhost:8082/graphiql)
* [subscription](http://localhost:8082/subscriptions)

Use [playground](http://localhost:8082/playground) to execute queries and browse schema
Use [graphiql](http://localhost:8082/graphiql) to execute queries and browse schema
or [js-graphql](https://plugins.jetbrains.com/plugin/8097-js-graphql)

#### Query
```graphql
#default value
query helloWorld{
query default {
hello {
greeting
time
}
}

# with paramter
query helloRob{
hello(name:"Rob") {
#with input
query rob {
hello(name: "Rob") {
greeting
time
}
}
```
Expand Down
17 changes: 12 additions & 5 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ plugins {
id("io.spring.dependency-management") version "1.1.0"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
kotlin("kapt") version "1.7.22"
}

group = "de.rowi1de.graphql"
Expand All @@ -27,8 +26,6 @@ dependencies {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")

// GraphQL
implementation("com.expediagroup:graphql-kotlin-spring-server:6.3.0")

// Rest
implementation("org.springdoc:springdoc-openapi-kotlin:1.6.13") {
Expand All @@ -38,13 +35,23 @@ dependencies {
exclude("io.github.classgraph", "classgraph")
}

// GraphQL
implementation("org.springframework.boot:spring-boot-starter-graphql")

developmentOnly("org.springframework.boot:spring-boot-devtools")
annotationProcessor("org.springframework.boot:spring-boot-configuration-processor")

testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("org.springframework.security:spring-security-test")
kapt("org.springframework.boot:spring-boot-configuration-processor")
}
testImplementation("org.springframework.graphql:spring-graphql-test")

}
configurations {
compileOnly {
extendsFrom(configurations.annotationProcessor.get())
}
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf(
Expand Down
15 changes: 0 additions & 15 deletions graphql/.graphqlconfig

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
package de.rowi1de.reactive.graphql.model

import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import org.springframework.graphql.data.method.annotation.SchemaMapping
import java.time.ZonedDateTime

@GraphQLDescription("Simple World")


data class HelloGraphql(

private val name: String
) {
@GraphQLDescription("Say Hello")
val greeting: String
get() = "Hello $name!"

@GraphQLDescription("Time of greeting")
val time: String
get() = ZonedDateTime.now().toString()
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package de.rowi1de.reactive.graphql.mutation.employees

import com.expediagroup.graphql.server.operations.Mutation
import de.rowi1de.reactive.graphql.model.employees.Employee
import de.rowi1de.reactive.graphql.model.employees.NewEmployee
import de.rowi1de.reactive.service.employees.EmployeeService
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.MutationMapping
import org.springframework.stereotype.Controller

@Component
class EmployeesMutation(private val service: EmployeeService) : Mutation {
@Controller
class EmployeesMutation(private val service: EmployeeService) {

@MutationMapping
suspend fun newEmployee(newEmployee: NewEmployee): Employee = service.addEmployee(newEmployee)
}
10 changes: 6 additions & 4 deletions src/main/kotlin/de/rowi1de/reactive/graphql/query/BrokenQuery.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package de.rowi1de.reactive.graphql.query

import com.expediagroup.graphql.server.operations.Query
import de.rowi1de.reactive.graphql.model.HelloGraphql
import graphql.GraphqlErrorBuilder.newError
import graphql.execution.DataFetcherResult
import graphql.schema.DataFetchingEnvironment
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller

@Component
class BrokenQuery : Query {
@Controller
class BrokenQuery {

@QueryMapping
suspend fun broken(): HelloGraphql = TODO("I told you")

@QueryMapping
suspend fun partialBroken(env: DataFetchingEnvironment): DataFetcherResult<HelloGraphql> =
DataFetcherResult.newResult<HelloGraphql>()
.data(HelloGraphql("Broken"))
Expand Down
14 changes: 7 additions & 7 deletions src/main/kotlin/de/rowi1de/reactive/graphql/query/HelloQuery.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package de.rowi1de.reactive.graphql.query

import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import com.expediagroup.graphql.server.operations.Query
import de.rowi1de.reactive.graphql.model.HelloGraphql
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.Argument
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller

@Component
class HelloQuery : Query {
@Controller
class HelloQuery {

@GraphQLDescription("Simple Hello World Query")
@QueryMapping
suspend fun hello(
@GraphQLDescription("Who should we greet?") name: String? = null
@Argument name: String? = null
): HelloGraphql = HelloGraphql(name ?: "World")
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package de.rowi1de.reactive.graphql.query.employees

import com.expediagroup.graphql.server.operations.Query
import de.rowi1de.reactive.graphql.model.employees.Employees
import de.rowi1de.reactive.graphql.model.employees.Teams
import de.rowi1de.reactive.service.employees.EmployeeService
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.QueryMapping
import org.springframework.stereotype.Controller

@Component
class EmployeesQuery(private val service: EmployeeService) : Query {
@Controller
class EmployeesQuery(private val service: EmployeeService) {

@QueryMapping
suspend fun employees(): Employees = Employees(service.getEmployees())

@QueryMapping
suspend fun teams(): Teams = Teams(service.getTeams())
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package de.rowi1de.reactive.graphql.subscription

import com.expediagroup.graphql.generator.annotations.GraphQLDescription
import com.expediagroup.graphql.server.operations.Subscription
import de.rowi1de.reactive.graphql.model.HelloGraphql
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.SubscriptionMapping
import org.springframework.stereotype.Controller
import reactor.core.publisher.Flux
import java.time.Duration

@Component
class HelloSubscription : Subscription {
@GraphQLDescription("Greet every second")
@Controller
class HelloSubscription {
@SubscriptionMapping
suspend fun hello(name: String): Flux<HelloGraphql> = Flux.interval(Duration.ofSeconds(1))
.map { HelloGraphql("$name $it") }
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package de.rowi1de.reactive.graphql.subscription.employee

import com.expediagroup.graphql.server.operations.Subscription
import de.rowi1de.reactive.graphql.model.employees.Employee
import de.rowi1de.reactive.service.employees.EmployeeService
import kotlinx.coroutines.reactor.asFlux
import org.springframework.stereotype.Component
import org.springframework.graphql.data.method.annotation.SubscriptionMapping
import org.springframework.stereotype.Controller
import reactor.core.publisher.Flux

@Component
class EmployeeSubscription(private val service: EmployeeService) : Subscription {
@Controller
class EmployeeSubscription(private val service: EmployeeService) {
@SubscriptionMapping
suspend fun employees(): Flux<Employee> = service.employees().asFlux()
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package de.rowi1de.reactive.security

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.web.server.SecurityWebFilterChain

@EnableWebFluxSecurity
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
class SecurityConfig {

@Bean
Expand All @@ -19,7 +21,7 @@ class SecurityConfig {
// graphql
.pathMatchers(
"/graphql", // single graphql POST Endpoint for query / mutations / introspection
"/playground", // playground
"/graphiql", // playground
"/sdl", // schema
"/subscriptions" // apollo compatible websocket subscription
)
Expand Down
22 changes: 14 additions & 8 deletions src/main/resources/application.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
server:
port: 8082

graphql:
packages:
- "de.rowi1de.reactive.graphql"
subscriptions:
endpoint: subscriptions
keep-alive-interval: 1000

springdoc:
api-docs:
path: "/api-docs"
Expand All @@ -30,4 +23,17 @@ management:
endpoints:
web:
exposure:
include: metrics,health,prometheus,info,httptrace
include: metrics,health,prometheus,info,httptrace


spring:
graphql:
websocket:
path: /subscriptions
graphiql:
enabled: true
path: /graphiql
security:
user:
name: user
password: password
8 changes: 8 additions & 0 deletions src/main/resources/graphql/schema.graphqls
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
type Query {
hello(name: String): HelloGraphql!
}

type HelloGraphql{
greeting: String!
time: String!
}

0 comments on commit 04e29e4

Please sign in to comment.