Partie 3 - Controllers

Publié le 16/01/2025 Source : sfeir.dev

Jour 3 : construction des entités et des contrôleurs

Musique de fond pour l’article


L’heure est venue de bâtir les fondations de notre API GraphQL avec Spring Boot. Ce jour, nous allons forger nos entités Java, qui se dresseront fièrement en miroir des types définis dans notre schéma. Nous érigerons ensuite nos contrôleurs, équipés des annotations puissantes que Spring for GraphQL met à notre disposition.

Retour au schéma

Souvenez-vous du schéma que nous avons déterré précédemment :

type Author {
    id: ID!
    name: String!
    bio: String
    articles: [Article]
}

type Article {
    id: ID!
    title: String!
    content: String!
    author: Author!
}

type Query {
    getAuthors: [Author]
    getAuthorById(id: ID!): Author
    getArticles: [Article]
    getArticleById(id: ID!): Article
}

type Mutation {
    createAuthor(name: String!, bio: String): Author
    createArticle(title: String!, content: String!, authorId: ID!): Article
}

notre schéma GraphQL

Notre cap aujourd’hui, c’est de donner vie aux éléments de notre schéma, dans lequel nous avons défini les types Author et Article, accompagnés de requêtes et de mutations :

Nous disposons de deux options pour organiser nos contrôleurs : soit un contrôleur pour chaque entité (ArticleController et AuthorController), soit un contrôleur unique pour chaque type de requête (QueryController et MutationController).
Pour garder une architecture familière, j’ai opté pour la première option, reflétant ainsi la structure REST que nous connaissons bien.

Nos entités Java

Voici nos classes d’entité, fidèles reflets de notre schéma.

Article

@Entity
public class Article {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String title;
    private String content;
    
    @ManyToOne
    @JoinColumn(name = "author_id")
    private Author author;

    // Constructeur
    ...
    // Getter et Setter
    ...
}

classe Article

Author

@Entity
public class Author {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    private String bio;
    
    @OneToMany(mappedBy = "author", cascade = CascadeType.ALL)
    private List<Article> articles = new ArrayList<>();

    // Constructeur
    ...
    // Getter et Setter
    ...
}

classe Auteur

Ainsi, nous forgeons notre modèle de données en lui donnant forme et substance, sans complexité inutile.

Les controllers

AuthorController

@Controller
public class AuthorController {

    private final AuthorService authorService;

    public AuthorController(AuthorService authorService) {
        this.authorService = authorService;
    }

    @MutationMapping
    public Author createAuthor(@Argument String name, @Argument String bio) {
        return authorService.createAuthor(name, bio);
    }

    @QueryMapping
    public List<Author> getAuthors() {
        return authorService.getAuthors();
    }

    @QueryMapping
    public Author getAuthorById(@Argument Long id) {
        return authorService.getAuthorById(id).orElse(null);
    }
}

AuthorController

ArticleController

@Controller
public class ArticleController {

    private final ArticleService articleService;

    public ArticleController(ArticleService articleService) {
        this.articleService = articleService;
    }

    @MutationMapping
    public Article createArticle(@Argument String title, @Argument String content, @Argument Long authorId) {
        return articleService.createArticle(title, content, authorId);
    }

    @QueryMapping
    public List<Article> getArticles() {
        return articleService.getArticles();
    }

    @QueryMapping
    public Article getArticleById(@Argument Long id) {
        return articleService.getArticleById(id).orElse(null);
    }
}

ArticleController

Explications des annotations

Notre levier principal dans cette opération repose sur des annotations clé :

Nota Bene : les services et les repositories se construisent comme avec une API REST, sans particularité liée à GraphQL.


Ainsi s’achève notre avancée du jour. L’ossature de notre API GraphQL est en place, et demain, nous soumettrons ces éléments à l’épreuve des terribles tests unitaires afin de garantir que tout fonctionne comme prévu.

Précédémment

Partie 2 - le schéma dans GraphQL

Prochainement

Partie 4 - Tests unitaires