Das Einbinden eines Contracts ist ein zentraler Schritt in der Contract-First-Entwicklung, bei dem eine vorab definierte API-Spezifikation in ein bestehendes Projekt integriert wird. Dieser Prozess gewährleistet, dass die Implementierung der API strikt dem definierten Vertrag entspricht, was Konsistenz, Wartbarkeit und Zusammenarbeit zwischen verschiedenen Teams fördert. In diesem Kapitel erläutern wir die Schritte zur Einbindung eines Contracts in eine Spring Boot-Anwendung, illustrieren den Prozess mit praktischen Beispielen und geben Best Practices zur erfolgreichen Integration.
Erstellung oder Erhalt der API-Spezifikation
api.yaml oder api.json) oder
GraphQL-Schema-Datei.Nutzung von Tools zur Code-Generierung
Integration in das Spring Boot-Projekt
pom.xml (für Maven) oder
build.gradle (für Gradle).Implementierung der Geschäftslogik
Validierung und Testing
Wir demonstrieren den Prozess anhand einer einfachen Buchverwaltung-API.
Erstellen Sie eine Datei namens api.yaml im Verzeichnis
src/main/resources/ mit folgendem Inhalt:
openapi: 3.0.1
info:
title: Bücher API
description: Eine API zur Verwaltung von Büchern.
version: 1.0.0
servers:
- url: http://localhost:8080/api
paths:
/books:
get:
summary: Liste aller Bücher abrufen
responses:
'200':
description: Erfolgreiche Antwort
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Book'
post:
summary: Ein neues Buch erstellen
requestBody:
description: Buchdaten
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
responses:
'201':
description: Buch erstellt
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
/books/{id}:
get:
summary: Ein Buch anhand der ID abrufen
parameters:
- in: path
name: id
schema:
type: integer
format: int64
required: true
description: Die ID des Buches
responses:
'200':
description: Erfolgreiche Antwort
content:
application/json:
schema:
$ref: '#/components/schemas/Book'
'404':
description: Buch nicht gefunden
components:
schemas:
Book:
type: object
properties:
id:
type: integer
format: int64
title:
type: string
author:
type: string
required:
- title
- authorFügen Sie das OpenAPI Generator Maven Plugin zu Ihrer
pom.xml hinzu:
<build>
<plugins>
<!-- OpenAPI Generator Plugin -->
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
<version>6.3.0</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.basedir}/src/main/resources/api.yaml</inputSpec>
<generatorName>spring</generatorName>
<output>${project.build.directory}/generated-sources/openapi</output>
<configOptions>
<interfaceOnly>true</interfaceOnly>
<delegatePattern>true</delegatePattern>
</configOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>Führen Sie den folgenden Maven-Befehl aus, um den Code basierend auf der OpenAPI-Spezifikation zu generieren:
mvn clean installDies erzeugt die Server-Stubs und Modelle im Verzeichnis
${project.build.directory}/generated-sources/openapi.
Implementieren Sie die generierten Controller-Stubs mit der Geschäftslogik.
BookControllerImpl.java
package com.example.generated.api;
import com.example.generated.model.Book;
import com.example.generated.repository.BookRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import java.util.List;
import java.util.Optional;
@Controller
public class BookControllerImpl implements BookController {
private final BookRepository bookRepository;
public BookControllerImpl(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
@Override
public ResponseEntity<List<Book>> getBooks() {
List<Book> books = bookRepository.findAll();
return ResponseEntity.ok(books);
}
@Override
public ResponseEntity<Book> getBookById(Long id) {
Optional<Book> book = bookRepository.findById(id);
return book.map(ResponseEntity::ok)
.orElse(ResponseEntity.notFound().build());
}
@Override
public ResponseEntity<Book> createBook(Book book) {
Book savedBook = bookRepository.save(book);
return ResponseEntity.status(201).body(savedBook);
}
// Weitere Methoden (updateBook, deleteBook etc.)
}package com.example.generated.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Book {
private Long id;
private String title;
private String author;
}package com.example.generated.repository;
import com.example.generated.model.Book;
import org.springframework.stereotype.Repository;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
@Repository
public class BookRepository {
private final Map<Long, Book> bookStore = new ConcurrentHashMap<>();
private final AtomicLong idGenerator = new AtomicLong();
public Book save(Book book) {
if (book.getId() == null) {
book.setId(idGenerator.incrementAndGet());
}
bookStore.put(book.getId(), book);
return book;
}
public Optional<Book> findById(Long id) {
return Optional.ofNullable(bookStore.get(id));
}
public List<Book> findAll() {
return new ArrayList<>(bookStore.values());
}
public boolean deleteById(Long id) {
return bookStore.remove(id) != null;
}
}Nach der Implementierung können Sie die API testen, indem Sie
Anfragen an die definierten Endpunkte senden. Nutzen Sie Tools wie
Postman, cURL oder die automatisch
generierte Swagger UI unter
http://localhost:8080/swagger-ui.html, um die API zu
erkunden und zu testen.
curl -X POST "http://localhost:8080/api/books" \
-H "Content-Type: application/json" \
-d '{"title": "Spring Boot in Action", "author": "Craig Walls"}'{
"id": 1,
"title": "Spring Boot in Action",
"author": "Craig Walls"
}Detaillierte und klare Spezifikation erstellen
Wiederverwendbare Komponenten definieren
components, um Redundanzen zu vermeiden und die Wartbarkeit
zu erhöhen.Automatisierte Code-Generierung integrieren
Versionierung und Deprecation planen
Implementierung von Sicherheitsmechanismen
Regelmäßige Validierung und Synchronisation
Dokumentation und Schulung
Effiziente Fehlerbehandlung
Das Einbinden eines Contracts ist ein essenzieller Schritt in der Contract-First-Entwicklung, bei dem eine vorab definierte API-Spezifikation in ein Spring Boot-Projekt integriert wird. Durch die Nutzung von Tools wie dem OpenAPI Generator können Server-Stubs und Modelle automatisch aus der Spezifikation generiert werden, was die Konsistenz und Qualität der API sicherstellt. Die Implementierung der Geschäftslogik erfolgt in den generierten Stubs, während die Spezifikation als zentrale Quelle für Dokumentation und Validierung dient. Best Practices wie klare Spezifikationen, Wiederverwendbarkeit, automatisierte Tests, Versionierung und Sicherheitsimplementierungen gewährleisten eine effiziente und wartbare API-Entwicklung. Insgesamt fördert das Einbinden eines Contracts die Zusammenarbeit, reduziert Fehler und erhöht die Wartbarkeit und Skalierbarkeit von APIs.