Skip to main content

๐Ÿš€ CRUD Operations

Get full REST API with zero boilerplate code! The @Crud annotation automatically generates all standard CRUD endpoints for your entities.

โšก Quick Startโ€‹

1. Create Your Entityโ€‹

@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String description;
private Double price;
private Integer stock;

// Constructors, getters, setters...
}

2. Create Repositoryโ€‹

@Component
public interface ProductRepository extends BaseRepository<Product, Long> {
// Framework handles all basic operations automatically
}

3. Add @Crud Controllerโ€‹

@Component
@Crud(
entity = Product.class,
endpoint = "/api/products",
enablePagination = true,
enableSearch = true,
searchableFields = {"name", "description"}
)
public class ProductController {
// That's it! All CRUD endpoints are auto-generated
}

4. Start Using Your APIโ€‹

๐ŸŽ‰ You instantly get these endpoints:

MethodEndpointDescription
GET/api/products/{id}Get product by ID
POST/api/productsCreate new product
PUT/api/products/{id}Update product
DELETE/api/products/{id}Delete product
GET/api/products/search?name=laptopSearch products

๐Ÿ“‹ @Crud Configurationโ€‹

@Crud(
entity = Product.class, // Your JPA entity
endpoint = "/api/products", // Base URL path
enablePagination = true, // Adds ?page=1&size=10 support
enableSearch = true, // Adds /search endpoint
searchableFields = {"name", "description"}, // Fields to search in
enableExists = true // Adds /exists/{id} endpoint
)

Configuration Optionsโ€‹

OptionDefaultDescription
entityRequiredThe JPA entity class
endpointRequiredBase URL path for endpoints
enablePaginationfalseEnable pagination support
enableSearchfalseEnable search functionality
searchableFields{}Fields to search in (when search enabled)
enableExistsfalseEnable exists check endpoint

๐ŸŽจ Customizing Methodsโ€‹

Need custom logic? Simply override any method:

@Component
@Crud(entity = Product.class, endpoint = "/api/products")
public class ProductController {

private final ProductRepository productRepository;

public ProductController(ProductRepository productRepository) {
this.productRepository = productRepository;
}

// Override findAll to show only in-stock products
@CrudOverride(value = "Returns only in-stock products")
public Response findAll(Request request) {
var inStockProducts = productRepository.findAll().stream()
.filter(product -> product.getStock() > 0)
.toList();
return Response.json(ApiResponse.success("In-stock products retrieved", inStockProducts));
}

// All other methods (findById, create, update, delete) remain auto-generated
}

Manual Route Registration for Overridesโ€‹

When you override a method, register its route manually:

public static void main(String[] args) {
Router router = new Router();

// Manual registration for overridden methods
router.GET("/api/products", "findAll", ProductController.class);

Server server = new Server(router, config);
server.start(8080);
}

๐Ÿงช Testing Your APIโ€‹

Create Productโ€‹

curl -X POST -H "Content-Type: application/json" \
-d '{"name":"Gaming Laptop","description":"High-performance laptop","price":1299.99,"stock":5}' \
"http://localhost:8080/api/products"

Get All Productsโ€‹

curl "http://localhost:8080/api/products"

Get Product by IDโ€‹

curl "http://localhost:8080/api/products/1"

Search Productsโ€‹

curl "http://localhost:8080/api/products/search?name=laptop"

Update Productโ€‹

curl -X PUT -H "Content-Type: application/json" \
-d '{"name":"Updated Laptop","description":"Updated description","price":1199.99,"stock":3}' \
"http://localhost:8080/api/products/1"

Delete Productโ€‹

curl -X DELETE "http://localhost:8080/api/products/1"

๐Ÿ“Š Response Formatโ€‹

All CRUD endpoints return standardized responses:

{
"success": true,
"message": "Product retrieved successfully",
"data": {
"id": 1,
"name": "Gaming Laptop",
"description": "High-performance laptop",
"price": 1299.99,
"stock": 5
},
"timestamp": "2023-12-07T10:30:00"
}

๐Ÿ”ง Requirementsโ€‹

Before using @Crud, ensure you have:

  1. Entity Class: JPA annotated entity
  2. Repository: Interface extending BaseRepository<Entity, ID>
  3. Component Registration: Repository marked with @Component
  4. Database Configuration: Hibernate/JPA properly configured

๐Ÿ’ก Best Practicesโ€‹

โœ… Do'sโ€‹

  • Use meaningful entity and endpoint names
  • Enable search for user-facing entities
  • Override methods only when you need custom logic
  • Use @CrudOverride for documentation

โŒ Don'tsโ€‹

  • Don't forget manual route registration for overrides
  • Don't enable unnecessary features (keeps API clean)
  • Don't override methods unless you need custom behavior

๐Ÿ” Complete Exampleโ€‹

Check out the Simple CRUD Example for a working implementation with:

  • โœ… Product entity with validation
  • โœ… Repository implementation
  • โœ… Controller with one custom method
  • โœ… Complete test commands
  • โœ… Real-world usage patterns

๐ŸŽฏ Result: With just a few annotations, you get a complete REST API with all CRUD operations, search, pagination, and standardized responses!