spring-graphql
|
Works with
---
name: spring-graphql
description: |
license: MIT
---
# Spring for GraphQL - Quick Reference
> **Full Reference**: See [advanced.md](advanced.md) for DataLoader configuration, custom scalars, pagination implementation, GraphQL testing patterns, and subscription controllers.
> **Deep Knowledge**: Use `mcp__documentation__fetch_docs` with technology: `spring-graphql` for comprehensive documentation.
## Dependencies
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-graphql</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
```
## Configuration
```yaml
spring:
graphql:
graphiql:
enabled: true
path: /graphiql
schema:
locations: classpath:graphql/**/
path: /graphql
websocket:
path: /graphql
```
## Schema Definition
```graphql
type Query {
bookById(id: ID!): Book
allBooks: [Book!]!
}
type Mutation {
createBook(input: CreateBookInput!): Book!
}
type Book {
id: ID!
title: String!
author: Author!
}
input CreateBookInput {
title: String!
authorId: ID!
}
```
## Query Controller
```java
@Controller
public class BookController {
@QueryMapping
public Book bookById(@Argument String id) {
return bookRepository.findById(id).orElse(null);
}
@QueryMapping
public List<Book> allBooks() {
return bookRepository.findAll();
}
@SchemaMapping(typeName = "Book", field = "author")
public Author author(Book book) {
return authorRepository.findById(book.getAuthorId()).orElse(null);
}
}
```
## Mutation Controller
```java
@Controller
public class BookMutationController {
@MutationMapping
public Book createBook(@Argument CreateBookInput input) {
return bookService.create(input);
}
}
```
## BatchMapping (Solve N+1)
```java
@Controller
public class OptimizedBookController {
@BatchMapping
public Map<Book, Author> author(List<Book> books) {
List<String> authorIds = books.stream()
.map(Book::getAuthorId)
.distinct()
.toList();
Map<String, Author> authorsById = authorRepository.findAllById(authorIds)
.stream()
.collect(Collectors.toMap(Author::getId, a -> a));
return books.stream()
.collect(Collectors.toMap(
book -> book,
book -> authorsById.get(book.getAuthorId())
));
}
}
```
## Input Validation
```java
@MutationMapping
public Book createBook(@Argument @Valid CreateBookInput input) {
return bookService.create(input);
}
public record CreateBookInput(
@NotBlank @Size(min = 1, max = 200) String title,
@NotNull String authorId
) {}
```
## Error Handling
```java
@Component
public class CustomExceptionResolver extends DataFetcherExceptionResolverAdapter {
@Override
protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) {
if (ex instanceof BookNotFoundException) {
return GraphqlErrorBuilder.newError(env)
.errorType(ErrorType.NOT_FOUND)
.message(ex.getMessage())
.build();
}
return null;
}
}
```
## Security
```java
@Controller
public class SecuredBookController {
@QueryMapping
@PreAuthorize("hasRole('USER')")
public List<Book> allBooks() {
return bookRepository.findAll();
}
@MutationMapping
@PreAuthorize("hasRole('ADMIN')")
public Book createBook(@Argument CreateBookInput input) {
return bookService.create(input);
}
}
```
## When NOT to Use This Skill
- **REST APIs** - Use standard Spring MVC controllers
- **Standalone GraphQL** - Use graphql-java directly
- **Simple CRUD** - May be overkill, consider REST
- **File uploads** - GraphQL isn't optimized for large binary data
## Anti-Patterns
| Anti-Pattern | Problem | Solution |
|--------------|---------|----------|
| No @BatchMapping | N+1 queries on nested fields | Use @BatchMapping or DataLoader |
| Unbounded lists | Memory exhaustion | Implement pagination |
| Exposing entities | Schema tightly coupled to DB | Use DTOs/projections |
| No error handling | Stack traces exposed | Custom ExceptionResolver |
| GraphiQL in prod | Security risk | Disable in production |
## Quick Troubleshooting
| Problem | Diagnostic | Fix |
|---------|------------|-----|
| N+1 queries | Check SQL logs | Add @BatchMapping |
| Field not resolved | Check method name | Verify @SchemaMapping matches schema |
| Subscription not working | Check WebSocket config | Enable WebSocket support |
| Validation not applied | Check @Valid | Add @Validated to controller |
| Auth not working | Check security config | Add @PreAuthorize annotations |
## Best Practices
| Do | Don't |
|----|-------|
| Use @BatchMapping for N+1 | Fetch nested data individually |
| Define clear schema contracts | Over-expose internal models |
| Implement pagination | Return unbounded lists |
| Use input types for mutations | Use many scalar arguments |
| Add proper error handling | Expose stack traces |
## Production Checklist
- [ ] Schema well defined
- [ ] N+1 solved with BatchMapping
- [ ] Input validation enabled
- [ ] Error handling configured
- [ ] Security annotations applied
- [ ] Pagination implemented
- [ ] GraphiQL disabled in prod
- [ ] Query complexity limits
- [ ] Introspection controlled
## Reference Documentation
- [Spring for GraphQL Reference](https://docs.spring.io/spring-graphql/reference/)More API Design skills
lark-event
larksuite/cli
Lark/Feishu real-time event listening / subscribing / consuming: stream events as NDJSON via `lark-cli event consume <EventKey>` (covers IM messages/reactions/chat changes, Approval status changes, Task updates, VC meeting started/joined/ended, Minutes generated, Whiteboard updated, etc.). Use for Lark bots, real-time message processing, long-running subscribers, streaming webhook/push handlers. Supports `--max-events` / `--timeout` bounded runs and a stderr ready-marker contract — designed for AI agents running as subprocesses.
lark-contact
larksuite/cli
飞书 / Lark 通讯录:按姓名 / 邮箱解析成 open_id,或按 open_id 反查姓名 / 部门 / 邮箱 / 联系方式 / 个人状态 / 签名,以及按关键词搜索当前用户可见的机器人 / 智能体(agent)。当用户提到一个名字要下一步发消息 / 排日程,或拿到 open_id 想查具体信息时使用。不负责部门树遍历、按部门列员工、组织架构图,这类需求走原生 OpenAPI。
lark-openapi-explorer
larksuite/cli
飞书/Lark 原生 OpenAPI 探索:从官方文档库中挖掘未经 CLI 封装的原生 OpenAPI 接口。当用户的需求无法被现有 lark-* skill 或 lark-cli 已注册命令满足,需要查找并调用原生飞书 OpenAPI 时使用。

