
Spring Boot Rest Api Standards
Scaffold Spring Boot REST APIs with layered/clean architecture—domain, application, presentation, and JPA infrastructure—in a feature-based folder layout.
Overview
Spring Boot REST API Standards is an agent skill for the Build phase that structures REST APIs with layered clean architecture across domain, application, presentation, and JPA infrastructure.
Install
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill spring-boot-rest-api-standardsWhat is this skill?
- Feature-based package layout: domain, application, presentation, infrastructure
- Domain entities and ports without Spring in the core model layer
- Immutable application DTOs/records and @Service use-case beans
- REST controllers, mappers, and dedicated exception handlers
- JPA infrastructure adapters implementing domain repository ports
Adoption & trust: 1.4k installs on skills.sh; 271 GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your Spring Boot API sprawls into framework-coupled entities and controllers with no repeatable feature module layout.
Who is it for?
Indie developers building multi-feature Spring Boot APIs who want clean boundaries before the codebase grows past a few endpoints.
Skip if: Non-JVM stacks, serverless-only handlers without Spring, or greenfield projects that already standardize on a different architectural style you will not change.
When should I use this skill?
Implementing or refactoring Spring Boot REST APIs with layered domain, application, presentation, and persistence structure.
What do I get? / Deliverables
You implement new features with domain ports, application services, REST DTOs, and JPA adapters following a consistent package structure.
- Feature module skeleton (domain/application/presentation/infrastructure)
- Controller, DTO, and repository adapter patterns aligned to the standard
Recommended Skills
Journey fit
REST API structure, controllers, DTOs, and persistence adapters are core Build backend work for JVM SaaS and APIs. The skill encodes backend layering and Spring-specific REST patterns, not frontend, launch, or ops concerns.
How it compares
Use for opinionated Spring layering in-repo—not OpenAPI-only codegen or a one-shot CRUD snippet without domain separation.
Common Questions / FAQ
Who is spring-boot-rest-api-standards for?
Solo and small-team builders creating Spring Boot REST APIs who need a repeatable clean-architecture folder and class pattern per feature.
When should I use spring-boot-rest-api-standards?
During Build backend work when adding or refactoring REST features, defining DTOs and controllers, or splitting JPA from domain logic.
Is spring-boot-rest-api-standards safe to install?
It provides coding patterns only—review the Security Audits panel on this page and treat generated code like any agent output before merge.
SKILL.md
READMESKILL.md - Spring Boot Rest Api Standards
# Architecture Patterns for REST APIs ## Layered Architecture ### Feature-Based Structure ``` feature-name/ ├── domain/ │ ├── model/ # Domain entities (Spring-free) │ │ └── User.java │ ├── repository/ # Domain ports (interfaces) │ │ └── UserRepository.java │ └── service/ # Domain services │ └── UserService.java ├── application/ │ ├── service/ # Use cases (@Service beans) │ │ └── UserApplicationService.java │ └── dto/ # Immutable DTOs/records │ ├── UserRequest.java │ └── UserResponse.java ├── presentation/ │ └── rest/ # Controllers and mappers │ ├── UserController.java │ ├── UserMapper.java │ └── UserExceptionHandler.java └── infrastructure/ └── persistence/ # JPA adapters └── JpaUserRepository.java ``` ### Domain Layer (Clean Architecture) #### Domain Entity ```java package com.example.domain.model; import java.time.LocalDateTime; import java.util.Objects; public class User { private final UserId id; private final String name; private final Email email; private final LocalDateTime createdAt; private final LocalDateTime updatedAt; private User(UserId id, String name, Email email) { this.id = Objects.requireNonNull(id); this.name = Objects.requireNonNull(name); this.email = Objects.requireNonNull(email); this.createdAt = LocalDateTime.now(); this.updatedAt = LocalDateTime.now(); } public static User create(UserId id, String name, Email email) { return new User(id, name, email); } public User updateName(String newName) { return new User(this.id, newName, this.email); } public User updateEmail(Email newEmail) { return new User(this.id, this.name, newEmail); } // Getters public UserId getId() { return id; } public String getName() { return name; } public Email getEmail() { return email; } public LocalDateTime getCreatedAt() { return createdAt; } public LocalDateTime getUpdatedAt() { return updatedAt; } } // Value objects public class UserId { private final Long value; public UserId(Long value) { this.value = Objects.requireNonNull(value); if (value <= 0) { throw new IllegalArgumentException("User ID must be positive"); } } public Long getValue() { return value; } } public class Email { private final String value; public Email(String value) { this.value = Objects.requireNonNull(value); if (!isValid(value)) { throw new IllegalArgumentException("Invalid email format"); } } private boolean isValid(String email) { return email.contains("@") && email.length() > 5; } public String getValue() { return value; } } ``` #### Domain Repository Port ```java package com.example.domain.repository; import com.example.domain.model.User; import com.example.domain.model.UserId; import java.util.Optional; public interface UserRepository { Optional<User> findById(UserId id); void save(User user); void delete(UserId id); boolean existsByEmail(Email email); } ``` #### Domain Service ```java package com.example.domain.service; import com.example.domain.model.User; import com.example.domain.model.Email; import com.example.domain.repository.UserRepository; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor public class UserDomainService { private final UserRepository userRepository; public User registerUser(String name, String email) { Email emailObj = new Email(email); if (userRepository.existsByEmail(emailObj)) { throw new BusinessException("Email already exists"); } User user = User.create(UserId.generate(), name, emailObj); userRepository.save(user); return user; } } ``` ### Application Layer (Use Cases) #### Application Service ```java package