Fixed issue #95 (minnal auto generated resource tests doesn’t set back references while test objects)
Fixed issue #96 (Exception Mapping is broken)
Exception Handling
This version supports custom exception handling for specific exceptions,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | public class MyApplication extends Application {
protected void mapExceptions() {
addExceptionHandler(ConstraintViolationException.class, new ConstraintViolationExceptionHandler());
}
public static class ConstraintViolationExceptionHandler implements ExceptionHandler {
@Override
public void handle(Request request, Response response, Throwable exception) {
ConstraintViolationException ex = (ConstraintViolationException) exception;
List<FieldError> errors = new ArrayList<FieldError>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
errors.add(new FieldError(Inflector.underscore(violation.getPropertyPath().toString()), violation.getMessage(), violation
.getInvalidValue()));
}
Map<String, List<FieldError>> message = new HashMap<String, List<FieldError>>();
message.put("field_errors", errors);
response.setStatus(HttpResponseStatus.UNPROCESSABLE_ENTITY);
response.setContent(message);
}
}
}
|
Fixed issue #97 (Add support javax.validation)
Fixed issue #98 (Sort APIs in the Swagger)
This release has upgrades to the latest version of Swagger and ActiveJPA. With these upgrades, minnal has support for Swagger spec version 1.2 and JPA 2.1.
Note: The swagger base url has changed from this version. It will be of the format /api/<application-name>/api-docs
A bunch of issues have been fixed in this release. Also added a sample petclinic application (from spring examples) using minnal.
This release has fixes for the below blocker bugs.
Fixed issue #30 (Build support for Authorization)
Authorizing the routes
This version has got support for authorizing the routes with annotations (if you use minnal-instrumentation) and without annotations (via the route definitions). To use the authorization support, you will have to include minnal-security in your pom.xml file.
Below is a sample code to set up auth permissions for routes via the route definition,
1 2 3 4 5 6 7 | public class OrderApplication extends Application<OrderConfiguration> {
@Override
protected void defineRoutes() {
resource(OrderResource.class).builder("/hello").action(HttpMethod.GET, "helloWorld")
.attribute(Authorizer.PERMISSIONS, "permission1,permission2");
}
}
|
The same can be achieved through annotations using the minnal-instrumentation module,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | @AggregateRoot
@Entity
@Table(name="Orders")
@SecureMultiple({
@Secure(method=Method.POST, permissions="CREATE_ORDER"),
@Secure(method=Method.PUT, permissions="EDIT_ORDER")
})
public class Order extends Model {
@OneToMany(cascade=CascadeType.ALL, orphanRemoval=true)
@JoinColumn(name="orderId")
@JsonManagedReference
@Secure(method=Method.DELETE, permissions="DELETE_ITEM")
private Set<OrderItem> orderItems = new HashSet<OrderItem>();
@Action(value="cancel")
@Secure(method=Method.PUT, permissions="CANCEL_ORDER")
public void cancel(String reason) {
setStatus(Status.cancelled);
setCancellationReason(reason);
}
}
|
Fixed issue #61 (Fixes in case conversion from under_scores to camelCase)
Fixed issue #49 (Support including & excluding fields in the json/xml response)
Dynamically including and excluding fields in the response
This version of minnal has support for dynamically including or excluding fields in the json response. This is quite useful when returning back a deeply nested entity or entities with collections. If combined with JPA lazy loading, you can avoid firing unwanted db sqls and increase the performance of the API. Below is a sample usage
1 2 | GET /orders?exclude=created_at,order_items,payments
GET /orders?include=order_items
|
Fixed issue #57 (Unable to create manual routes to an auto created resource)
Fixed issue #59 (Swagger API doesn’t show operations for applications with base path other than ‘/’)
Fixed issue #60 (404 errors are not thrown)
Fixed issue #54 - Move maven repo
Minnal uses github for hosting the maven artifacts. The artifacts were pushed to a different branch in the minnal project and this has become a bottleneck now as the size of the repository has grown. This changed moves the maven repository to a different github project. Please change your maven repository in the pom file to the location below.
1 2 3 4 5 6 7 8 9 | <repository>
<id>minnal-releases-repo</id>
<url>https://raw.github.com/minnal/mvn-repo/master/releases</url>
</repository>
<repository>
<id>minnal-snapshots-repo</id>
<url>https://raw.github.com/minnal/mvn-repo/master/snapshots</url>
</repository>
|
Fixed issue #24 - Implement @Action handler. PUT calls will invoke methods marked with this annotation
Auto generate routes for your domain operations
You can now generate routes for your domain operations using the annotation @Action
. A method marked with this annotation will automatically show up in the routes. This annotation is applicable only for domain models annotated with @AggregateRoot
. Minnal enforces the users to follow stringent domain modeling. Any operations involving the children of the aggregate root should be driven by the root. For instance if you want to cancel 5 quantities of an order item, you should call cancel(orderItem, 5) on order which in turn would call orderItem to cancel 5 quantities. This way, any domain check (like can the order item be cancelled in the current state of order etc.. ) can be done at order level.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | /**
* This method will expose the route /orders/{order_id}/cancel
* Your payload should be a json structure with keys mapping to the name of the method arguments
* In this scenario the payload would be {"reason": "some cancellation reason"}
* Minnal will automatically call this method with the reason taken from payload
*/
@Action(value="cancel")
public void cancel(String reason) {
setStatus(Status.cancelled);
setCancellationReason(reason);
}
/**
* This method will expose the route /orders/{order_id}/order_items/{order_item_id}/cancel
* Your payload should be a json structure with keys mapping to the name of the method arguments
* In this scenario the payload would be {"reason": "some cancellation reason"}
* Minnal will automatically call this method with the reason taken from payload
*/
@Action(value="cancel", path="orderItems")
public void cancelOrderItem(OrderItem orderItem, String reason) {
orderItem.cancel(reason);
}
|
Fixed issue #52 - ApplicationConfig should be globally accessible within an application
Globally accessible application context
Minnal now allows configurations to be accessible from any where in the request flow. ApplicationContext
will give you access to the configurations specific to the current request like RouteConfiguration
, ResourceConfiguration
and ApplicationConfiguration
. Below is the sample usage,
1 2 3 | ApplicationContext.instance().getApplicationConfiguration();
ApplicationContext.instance().getResourceConfiguration();
ApplicationContext.instance().getRouteConfiguration();
|
Fixed issue #50 - Support for excluding certain routes from the API
Support for excluding certain routes from the API
You can now exclude that routes that you don’t want to expose to the clients from the API list. This can be done at the aggregate root level as well as at the collection level,
1 2 3 4 5 6 7 8 9 | // This aggregate root will expose only read apis
@Entity
@AggregateRoot(create=false, update=false, delete=false, read=true)
public class Order extends Model {
// The order items collection read api wont be exposed
@Collection(read=false)
private Set<OrderItem> orderItems;
}
|
Fixed issue #15 - Auto Generate Test cases
Auto generating test code
Minnal now can generate test cases for the routes it generated. This is a step towards the goal of speeding up the service development. The minnal-example module has test cases that are auto generated by minnal
1 2 3 4 5 6 7 8 9 10 | $ minnal -help generate-tests
Generates the resource tests
Usage: generate-tests [options]
Options:
-packages
The list of packages
Default: []
-projectDir
The project directory
Default: /Users/ganeshs/doc
|
Sample usage,
1 | $ minnal generate-tests -packages com.example.shoppingcart
|
Fixed issue #45 - Swagger API documentation bug
Fixed issue #5 - Support for bulk retrieval/create/update/delete
Support for bulk operations
This release will have support for bulk retrievals, updates, creates and deletes. Backward compatibility has been ensured and so you don’t have to change your api’s.
Bulk retrieval
When the identifiers are comma-seperated in the GET call, minnal would return back an array instead of a single object. When the identifiers are not separated by comma, a single object would be returned. A couple of examples below,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | GET /orders/1,2
[{
"id": 1,
"customer_email": "ganeshs@flipkart.com"
}, {
"id": 2,
"customer_email": "ganeshs@flipkart.com"
}]
GET /orders/1/order_items/12,13
[{
"id": 12,
"order_id": 1,
"quantity": 1
}, {
"id": 13,
"order_id": 1,
"quantity": 1
}]
|
Bulk create
In the POST call, if an array is passed, minnal will iterate over the array and create each of them in a single transactional scope.
1 2 3 4 5 6 7 8 9 10 11 | POST /orders/1/order_items
[{
"order_id": 1,
"quantity": 2,
"product_id": "xyz"
}, {
"order_id": 1,
"quantity": 1,
"product_id": "abc"
}]
|
Bulk update
If you pass in a comma-separated identifiers, the same payload will be applied for all the objects resolved by the identifiers. Note: this assumes the payload is same for all the objects to be updated.
1 2 3 4 5 | PUT /orders/1,2,3
{
"customer_email": "ganeshs@flipkart.com"
}
|
Bulk delete
If identifiers are separated by comma, all of them will be deleted in the same transactional scope.
1 | DELETE /orders/1/order_items/12,13
|
Fixed issue #44 - Nested objects are not updated in the PUT call
Fixed enhancement #4 - Support pagination in the list/search command
Pagination
This release has support for pagination in the search APIs. This change is completely backward compatible and shouldn’t impact your existing APIs.
1 2 3 4 5 6 7 8 9 | GET /orders?customer_email=ganeshs@flipkart.com&page=1&per_page=10
{
"page": 1,
"per_page": 10,
"total": 125,
"count": 10,
"data": []
}
|