Repository navigation
spring-xpose 4.0.0
Highlights
Search — POST /api/<path>/search
Add Operation.SEARCH to expose and declare which filters each field accepts:
@Entity
@ExposeEntity(path = "products", pageable = true,
expose = {Operation.FIND_ALL, Operation.FIND_BY_ID, Operation.CREATE,
Operation.UPDATE, Operation.DELETE, Operation.SEARCH})
public class Product {
@ExposeField(filterOperations = {FilterOperation.EQ, FilterOperation.LIKE})
private String name;
@ExposeField(filterOperations = {FilterOperation.GTE, FilterOperation.LTE})
private BigDecimal price;
@ManyToOne
@ExposeField(filterOperations = {FilterOperation.EQ, FilterOperation.IN})
private Category category;
@ElementCollection
@ExposeField(filterOperations = {FilterOperation.IN, FilterOperation.NOT_IN, FilterOperation.IS_NULL})
private List<String> tags;
}curl -X POST "http://localhost:8080/api/products/search?page=0&size=20&sort=price,desc" \
-H "Content-Type: application/json" \
-d '{"name_like": "laptop", "price_lte": 2000, "categoryId_in": [1, 2], "tags_in": ["sale"]}'- Operations:
EQ,NE,GT,GTE,LT,LTE,LIKE(case-insensitive contains),IN,NOT_IN,IS_NULL.EQuses the field name as its key; every other operation uses<field>_<operation>(price_gte,status_not_in,deletedAt_is_null). - Every key is optional and keys are combined with AND;
{}returns every record. - Collections (
@ElementCollection, MongoDB arrays):IN/NOT_INmean has any / has none of the values;IS_NULLmeans null or empty. - Relations filter by the related id:
"categoryId": 5,"suppliers_in": [1, 2]. - Paging and sorting with
pageable = true(page,size,sortquery parameters). - A read: secured with
readRoles, notwriteRoles; safe to retry. - Strict: an unknown key — a typo, an operation the field doesn't declare, a hidden field — is a
400that lists the allowed keys; values are type-checked (400keyed by the JSON key). - Checked at compile time: e.g.
LIKEon a number, ranges on a non-comparable type, or filters on a hidden field fail the build. - Swagger UI: a typed request-body schema and a ready-to-send example.
- JPA and MongoDB.
Why POST: a GET cannot reliably carry a request body, and a body keeps filters typed and free of URL length limits. Serving search over the HTTP QUERY method (RFC 10008) is planned once Spring supports it, with the same body.
Hide fields with @ExposeField(hidden = true)
@ExposeField(hidden = true)
private String passwordHash; // stored, never returned or accepted by the APILeft out of both the response and the request DTO; works on scalar fields, relations and MongoDB fields.
Clearer 400 for unreadable request bodies
The urn:springxpose:malformed-body problem now names the failing property — detail says where, and errors is keyed by the JSON path:
{ "type": "urn:springxpose:malformed-body", "status": 400,
"detail": "The request body is invalid at 'price': Cannot deserialize value of type `java.math.BigDecimal` from String \"abc\": not a valid representation",
"errors": { "price": "Cannot deserialize value of type `java.math.BigDecimal` from String \"abc\": not a valid representation" } }Paging documented correctly in OpenAPI
With pageable = true, Swagger UI shows page, size and sort as optional query parameters.
Breaking changes
-
ignoredFieldsis removed from@ExposeEntityand@ExposeDocument. Mark each field instead:// 3.x @ExposeEntity(path = "users", ignoredFields = {"passwordHash"}) public class User { private String passwordHash; } // 4.0 @ExposeEntity(path = "users") public class User { @ExposeField(hidden = true) private String passwordHash; }
-
Malformed-body
400responses gained anerrorsproperty and a differentdetailtext (see above). Clients that parsedetailshould switch toerrors.
Fixes
- Entities with a generic or array field (
List<String>,Set<Integer>,byte[]) now generate their DTOs.
Upgrading
- Bump
spring-xpose-starterandspring-xpose-processorto4.0.0. - Replace every
ignoredFields = {...}with@ExposeField(hidden = true)on those fields. - Optional: add
Operation.SEARCHand@ExposeField(filterOperations = ...)where clients need filtering.
Sample project: spring-xpose-sample-rest