Skip to content

Commit c6ec2d7

Browse files
authored
feat: add graphql service (#11)
Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
1 parent 8bb1ddf commit c6ec2d7

10 files changed

Lines changed: 124 additions & 3 deletions

File tree

.gitpod.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ vscode:
55
extensions:
66
- linuxsuren.api-testing
77
- vscjava.vscode-maven
8+
- redhat.java

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ Run E2E testing:
77
make build-image test-e2e
88
```
99

10+
## GraphQL
11+
You can visit it via: http://localhost:8080/graphiql?path=/graphql
12+
1013
## OpenAPI
1114
You can visit the swagger UI with the following address:
1215

e2e/test-suite.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,33 @@ items:
3030
Authorization: Basic YWRtaW46MTIzNDU2
3131
expect:
3232
body: cookies are empty
33+
34+
## GraphQL
35+
- name: queryBookById
36+
request:
37+
api: /graphql
38+
method: POST
39+
header:
40+
Content-Type: application/json
41+
body: |
42+
{
43+
"query": "query xxx {\n bookById(id: \"book-1\") {\n id\n name\n }\n}",
44+
"operationName": "xxx"
45+
}
46+
expect:
47+
bodyFieldsExpect:
48+
data.bookById.name: Effective Java
49+
- name: queryBookById-not-found
50+
request:
51+
api: /graphql
52+
method: POST
53+
header:
54+
Content-Type: application/json
55+
body: |
56+
{
57+
"query": "query xxx {\n bookById(id: \"book\") {\n id\n name\n }\n}",
58+
"operationName": "xxx"
59+
}
60+
expect:
61+
verify:
62+
- data.bookById == nil

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@
2727
<artifactId>spring-boot-starter-security</artifactId>
2828
</dependency>
2929

30+
<dependency>
31+
<groupId>org.springframework.boot</groupId>
32+
<artifactId>spring-boot-starter-graphql</artifactId>
33+
</dependency>
34+
3035
<dependency>
3136
<groupId>org.springdoc</groupId>
3237
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>

src/main/java/io/github/devopsws/demo/config/WebSecurityConfig.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,22 @@
99
import org.springframework.security.core.userdetails.UserDetailsService;
1010
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
1111
import org.springframework.security.web.SecurityFilterChain;
12+
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
13+
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
14+
import static org.springframework.security.config.Customizer.withDefaults;
1215

1316
@Configuration
1417
@EnableWebSecurity
18+
// @EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
1519
public class WebSecurityConfig {
1620

1721
@Bean
1822
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
1923
http.authorizeHttpRequests((requests) -> requests
20-
.requestMatchers("/health", "/v3/api-docs").permitAll()
21-
.anyRequest().authenticated()).httpBasic();
24+
.requestMatchers("/health", "/v3/api-docs", "/graphql", "/graphiql").permitAll()
25+
.anyRequest().authenticated())
26+
.httpBasic(withDefaults())
27+
.csrf(AbstractHttpConfigurer::disable);
2228

2329
return http.build();
2430
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.github.devopsws.demo.model;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
public record Author (String id, String firstName, String lastName) {
7+
8+
private static List<Author> authors = Arrays.asList(
9+
new Author("author-1", "Joshua", "Bloch"),
10+
new Author("author-2", "Douglas", "Adams"),
11+
new Author("author-3", "Bill", "Bryson")
12+
);
13+
14+
public static Author getById(String id) {
15+
return authors.stream()
16+
.filter(author -> author.id().equals(id))
17+
.findFirst()
18+
.orElse(null);
19+
}
20+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.github.devopsws.demo.model;
2+
3+
import java.util.Arrays;
4+
import java.util.List;
5+
6+
public record Book (String id, String name, int pageCount, String authorId) {
7+
8+
private static List<Book> books = Arrays.asList(
9+
new Book("book-1", "Effective Java", 416, "author-1"),
10+
new Book("book-2", "Hitchhiker's Guide to the Galaxy", 208, "author-2"),
11+
new Book("book-3", "Down Under", 436, "author-3")
12+
);
13+
14+
public static Book getById(String id) {
15+
return books.stream()
16+
.filter(book -> book.id().equals(id))
17+
.findFirst()
18+
.orElse(null);
19+
}
20+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package io.github.devopsws.demo.service;
2+
3+
import org.springframework.graphql.data.method.annotation.Argument;
4+
import org.springframework.graphql.data.method.annotation.QueryMapping;
5+
import org.springframework.graphql.data.method.annotation.SchemaMapping;
6+
import org.springframework.stereotype.Controller;
7+
import io.github.devopsws.demo.model.Book;
8+
import org.springframework.security.access.annotation.Secured;
9+
import org.springframework.security.access.prepost.PreAuthorize;
10+
11+
@Controller
12+
public class GraphQL {
13+
@QueryMapping
14+
// @Secured("ROLE_USER")
15+
// @PreAuthorize("hasRole('USER')")
16+
public Book bookById(@Argument String id) {
17+
return Book.getById(id);
18+
}
19+
}
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
1+
# https://spring.io/guides/gs/graphql-server/
2+
spring.graphql.graphiql.enabled=true
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
type Query {
2+
bookById(id: ID): Book
3+
}
4+
5+
type Book {
6+
id: ID
7+
name: String
8+
pageCount: Int
9+
author: Author
10+
}
11+
12+
type Author {
13+
id: ID
14+
firstName: String
15+
lastName: String
16+
}

0 commit comments

Comments
 (0)