The REST API framework built for production SaaS.
Multi-tenant • Audit Trail • Exports • Real-time • Owner Security
Every production REST API needs:
- ✅ Multi-tenancy — automatic data isolation per customer
- ✅ Complete audit trail — who changed what, when, with full history
- ✅ Idempotency keys — prevent duplicate requests (double-click, network retry)
- ✅ Export to Excel/PDF — business users demand it
- ✅ Real-time updates — WebSocket events on data changes
- ✅ Owner-based security — users can only modify their own resources
- ✅ Rate limiting — protect your API from abuse
- ✅ Soft delete — never lose data, always recoverable
FlashAPI gives you all of this out of the box — no custom code, just annotations.
@Entity
@FlashEntity(audit = true)
@FlashSecured(ownerField = "author", ownerAdminRoles = "ADMIN")
@FlashMultiTenant(field = "tenantId")
public class Invoice {
@Id @GeneratedValue
private Long id;
@ManyToOne
private User author; // Owner-based security
private String tenantId; // Multi-tenant isolation
private BigDecimal amount;
private String status;
}You instantly get:
POST /api/invoices # Auto-inject author + tenant
GET /api/invoices # Filtered by tenant, only see your own
GET /api/invoices/{id} # 403 if not owner (unless ADMIN)
PUT /api/invoices/{id} # Owner or ADMIN only
DELETE /api/invoices/{id} # Soft delete with restore
GET /api/invoices/{id}/history # Complete audit trail
GET /api/invoices/export?format=pdf # Instant PDF exportWebSocket real-time:
ws://localhost:8080/api/ws
→ { type: "ENTITY_CREATED", entity: "Invoice", data: {...} }The hidden cost of "just write it yourself"
When you start a new Spring Boot project, you write:
- Repositories → boilerplate
- Services → boilerplate + business logic
- Controllers → boilerplate + request/response mapping
- DTOs → endless mapping code
- Pagination → reinvent the wheel
- Filtering → parse query params manually
- Exports → POI/Jasper integration from scratch
- Audit → custom interceptors + database design
- Multi-tenancy → filters everywhere, easy to mess up
- Security → repetitive authorization logic
Result: 2-3 weeks before your first real feature.
// This is your ENTIRE backend for a multi-tenant invoice system
@Entity
@FlashEntity(audit = true)
@FlashSecured(ownerField = "author")
@FlashMultiTenant(field = "tenantId")
public class Invoice { /* fields */ }No repositories. No services. No controllers. No DTOs.
Just your domain model with production-grade features built-in.
| Feature | Spring Data REST | FlashAPI |
|---|---|---|
| Philosophy | Prototype tool | Production framework |
| Best for | Admin panels, POCs | Production SaaS APIs |
| CRUD auto-generation | ✅ | ✅ |
| Pagination & sorting | ✅ | ✅ |
| Multi-tenancy (tenantField) | ❌ | ✅ |
| Audit trail with history | ❌ | ✅ |
| Owner-based security | ❌ | ✅ |
| Export CSV/Excel/PDF | ❌ | ✅ |
| Soft delete + restore | ❌ | ✅ |
| Rate limiting | ❌ | ✅ |
| Bulk operations | ❌ | ✅ |
| WebSocket real-time | ❌ | ✅ |
| Webhooks | ❌ | ✅ |
| Full-text search | ❌ | ✅ |
| Field selection | ❌ | ✅ |
| Declarative counters | ❌ | ✅ |
| Feature guard (SaaS plans) | ❌ | ✅ |
| Lifecycle hooks | ❌ | ✅ |
| Custom templates (PDF) | ❌ | ✅ |
When to use Spring Data REST:
- Internal admin panels
- Rapid prototyping
- Simple CRUD with no business logic
When to use FlashAPI:
- Production SaaS APIs
- Multi-tenant applications
- Compliance/audit requirements
- Need exports, real-time, complex security
<dependency>
<groupId>io.github.hackermanme</groupId>
<artifactId>spring-flashapi</artifactId>
<version>3.1.2</version> <!-- x-release-please-version -->
</dependency>Get a complete production-ready API instantly:
- Zero boilerplate — annotate your entity, get a full CRUD API
- Progressive disclosure — FlashAPI recedes as you define your own services or controllers
- Dynamic filtering —
?price.gte=100&name.contains=phonewith 11 operators - Relation filters — filter by joined entities (e.g.,
?category.id=1) - Full-text search —
?search=laptopacross all String fields - Pagination & sorting —
?page=0&size=20&sort=name,asc - Export — CSV, Excel, and PDF with one query param (
?format=csv) - Bulk operations — batch create, update, delete with per-item error reporting
- Relations & expand — automatic FK resolution from
categoryIdin body,?expand=category,tagsto include related entities - Field selection —
?fields=id,namefor sparse fieldsets (reduce payload size) - Typed errors — production-ready error responses with proper HTTP status codes
- Intelligent caching — transparent response caching with auto-invalidation on writes
- Rate limiting — per-IP token bucket, configurable per entity
- WebSocket real-time — live CRUD events via raw WebSocket at
/api/ws - OpenAPI documentation — auto-generated spec + Swagger UI at
/api/docs(includes custom controllers) - Soft delete — timestamp-based with restore endpoint
- Audit trail — who changed what, when, with field-level diffs
- Field visibility —
@FlashReadOnly,@FlashWriteOnly,@FlashHidden,@FlashExportExclude - Lookup field — use UUID or any unique field in URLs instead of exposing auto-increment IDs
- Custom services — implement
FlashCrudOperations<T, ID>to add business logic - Authorization —
@FlashSecuredfor role-based and owner-based endpoint access control - Auto-inject user —
currentUserFieldauto-sets the authenticated user on CREATE, stripped from body - Principal resolver —
FlashPrincipalResolverfor custom identity extraction (works withownerFieldandcurrentUserField) - Declarative counters —
@FlashCounterfor auto-maintained denormalized counts (likes, comments) - Feature guard —
maxRecordsfor record-count limits with dynamicPlanLimitResolver - Multi-tenancy —
tenantFieldfor automatic data isolation per tenant - Webhooks —
webhookfor real-time event notifications to external systems - Lifecycle hooks —
@FlashBeforeCreate,@FlashAfterUpdate, etc. for injecting business logic at CRUD events - Spring Security aware — audit resolves current user automatically
- Type-safe IDs — supports Long, Integer, UUID, String
<dependency>
<groupId>io.github.hackermanme</groupId>
<artifactId>spring-flashapi</artifactId>
<version>3.1.2</version> <!-- x-release-please-version -->
</dependency>@SpringBootApplication
@EnableFlashApi
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}@Entity
@FlashEntity(softDelete = true, audit = true, trackFields = true)
public class User {
@Id @GeneratedValue
@FlashReadOnly
private Long id;
private String email;
@FlashWriteOnly
private String password;
@FlashReadOnly
private LocalDateTime createdAt;
@FlashHidden
private String internalToken;
}./mvnw spring-boot:runFlashAPI follows a simple philosophy: provide everything, recede when you take over.
| Level | You write | FlashAPI handles |
|---|---|---|
| 1. Zero config | @FlashEntity on your class |
Everything |
| 2. Custom service | A ProductService bean |
Routing, serialization, errors |
| 3. Custom controller | Your own @RestController |
Nothing (backs off) |
// Level 2: FlashAPI detects this and delegates to it
@Service
public class ProductService implements FlashCrudOperations<Product, Long> {
@Override
public Product create(Map<String, Object> data) {
// your business logic here
}
// ...
}All list endpoints support full-text search across String fields:
GET /api/products?search=laptop
Combine with filters, sort, and pagination:
GET /api/products?search=pro&price.gte=500&sort=name,asc&page=0&size=10
All list endpoints support dynamic filtering:
| Operator | Example | Description |
|---|---|---|
eq |
?status=active |
Equals (default) |
neq |
?status.neq=archived |
Not equals |
gt / gte |
?price.gte=100 |
Greater than (or equal) |
lt / lte |
?stock.lte=10 |
Less than (or equal) |
contains |
?name.contains=phone |
Case-insensitive contains |
startswith |
?name.startswith=sam |
Starts with |
endswith |
[email protected] |
Ends with |
isnull |
?deletedAt.isnull=true |
Is null |
in |
?status.in=active,pending |
In list |
Every entity with LIST access automatically gets an export endpoint:
GET /api/products/export?format=csv
GET /api/products/export?format=xlsx
GET /api/products/export?format=pdf
All filters and sorting apply to exports too:
GET /api/products/export?format=csv&price.gte=100&sort=name,asc
| Format | Dependency required | Description |
|---|---|---|
| CSV | None | Always available, UTF-8 with BOM |
| XLSX | org.apache.poi:poi-ooxml |
Streaming Excel (constant memory) |
net.sf.jasperreports:jasperreports |
Auto-generated table or custom template |
Place a .jrxml file matching your entity path in classpath:flashapi/reports/:
src/main/resources/flashapi/reports/products.jrxml
FlashAPI will use your template and feed it the filtered data. If no template exists, a clean table layout is generated dynamically.
Available parameters in your template:
ENTITY_NAME— the entity name (e.g., "Product")RECORD_COUNT— total number of records in this export
flashapi:
export:
max-rows: 0 # 0 = unlimited, set a cap to prevent abuse
reports-path: flashapi/reports # classpath location for .jrxml templatesAdd spring-boot-starter-websocket and FlashAPI automatically broadcasts CRUD events:
const ws = new WebSocket("ws://localhost:8080/api/ws");
ws.onopen = () => ws.send(JSON.stringify({ action: "subscribe", topic: "/topic/entities" }));
ws.onmessage = (e) => console.log(JSON.parse(e.data));
// → { type: "ENTITY_CREATED", entity: "Product", data: {...}, timestamp: "..." }Events: ENTITY_CREATED, ENTITY_UPDATED, ENTITY_DELETED, ENTITY_RESTORED.
Topics: /topic/entities (all) or /topic/{entity} (specific, lowercase).
See WebSocket docs for configuration and security.
Use application.yml or application.properties — both work identically.
application.yml:
flashapi:
base-path: /api
default-page-size: 20
max-page-size: 100
audit:
enabled: true
soft-delete:
column-name: deletedAt
export:
max-rows: 0
reports-path: flashapi/reports
bulk:
max-items: 100
websocket:
enabled: trueapplication.properties:
flashapi.base-path=/api
flashapi.default-page-size=20
flashapi.max-page-size=100
flashapi.audit.enabled=true
flashapi.soft-delete.column-name=deletedAt
flashapi.export.max-rows=0
flashapi.export.reports-path=flashapi/reports
flashapi.bulk.max-items=100
flashapi.websocket.enabled=true| Guide | Description |
|---|---|
| Getting Started | Installation and first steps |
| Annotations | Full annotation reference |
| Custom Services | Taking control of business logic |
| Export | CSV, Excel, and PDF export |
| Bulk Operations | Batch create, update, delete |
| Relations & Expand | Include related entities in responses, automatic FK resolution |
| Field Selection | Sparse fieldsets with ?fields= query parameter |
| Error Handling | HTTP status codes, error formats, and validation |
| Relation Filters | Filter by joined entities (?category.id=5) |
| Lifecycle Hooks | Inject business logic at CRUD events |
| Cache | Intelligent response caching |
| Rate Limiting | Per-IP rate limiting |
| Feature Guard | Record-count limits & SaaS plan enforcement |
| Search | Full-text search across fields |
| OpenAPI | Auto-generated Swagger UI & spec |
| Security | @FlashSecured role-based authorization |
| Current User Field | Auto-inject authenticated user into entities |
| Counters | Declarative denormalized counters (@FlashCounter) |
| Multi-Tenancy | Automatic data isolation per tenant |
| WebSocket | Real-time CRUD events via raw WebSocket |
| Webhooks | Event notifications on data changes |
| Cookbook | CORS, security, Docker, monitoring, recipes |
| Soft Delete | Timestamp-based soft delete |
| Audit Trail | Change tracking and history |
| Configuration | All available properties |
| Migration Guide | Upgrading between major versions |
| Progressive Disclosure | The framework philosophy |
- Java 21+
- Spring Boot 3.2+
- Spring Data JPA (Hibernate or any JPA provider)
git clone https://github.com/HackermanMe/spring-flashapi.git
cd spring-flashapi
./mvnw verifyContributions are welcome! Please open an issue first to discuss what you'd like to change.