Load Entities
The Entities API allows you to load entities through the API in various ways:
-
Load Entity by ID loads a single entity by its unique identifier (ID).
-
Load List of Entities load all entities with pagination and sorting.
-
Load Entities via Search Filter allows you to filter for entities by filter criteria in the Request.
-
Load Entities via JPQL loads entities via pre-configuring named JPQL queries.
Load Entity by ID
The first way of loading an entity via the Entities API is by loading it via its ID. The corresponding endpoint for this is the Load Entity endpoint /entities/:entityName/:entityId
.
The :entityName
path parameter defines which entity type it is. The value is defined in the entity definition:
@JmixEntity
@Table(name = "SAMPLE_ORDER")
@Entity(name = "sample_Order") (1)
public class Order {
// ...
}
1 | The name attribute value sample_Order of the @Entity JPA annotation indicates the entityName parameter in the Entities API. |
The Load Entity endpoint returns a single instance in case it is found by its identifier. Otherwise, HTTP status code 404 - Not Found
is returned.
GET http://localhost:8080/rest
/entities
/sample_Order
/21021f78-edac-224b-e6f8-6e71e02a0f0d
{
"_entityName": "sample_Order", (1)
"_instanceName": "rest.sample.entity.Order-21021f78-edac-224b-e6f8-6e71e02a0f0d [detached]",
"id": "21021f78-edac-224b-e6f8-6e71e02a0f0d",
"date": "2020-12-13", (2)
"amount": 49.99,
"createdDate": "2021-02-06T12:03:38.049",
"createdBy": "admin",
"lastModifiedDate": "2021-02-06T12:03:38.049",
"version": 1
}
1 | Some metadata about the entity instance is returned as JSON keys (entityName , _instanceName and id ). |
2 | The JSON Object contains each business attribute as a key. |
Some attributes of the Order
entity are missing in the JSON, as by default only local attributes of the entity are loaded. In case of reference attributes should also be included in the response you need to use Fetch Plans as described below.
Using Fetch Plans
Which attributes are needed normally varies based on the clients' use-case, UIs, or integration scenario. Loading only the direct attributes of an entity is oftentimes not enough.
With only the ability to load each entity type in a dedicated request, it would require loading referenced entity information in subsequent requests. This would lead to N+1 query problems in the overall application. In particular, when interacting through HTTP, the corresponding overhead can be tremendous.
Therefore, the concept of Fetch Plans is also supported in the Load Entities API. With Fetch Plans you can configure a tree of attributes that should be loaded all in one batch from the database and transferred through the Load Entities API to the client.
The following example demonstrates how to load a list of Orders with additional information about the corresponding customer, the linked order lines, and even information about the product of that product line.
First, you need to register the fetch plan order-with-details
in the fetch-plans.xml
configuration file:
<fetchPlans xmlns="http://jmix.io/schema/core/fetch-plans">
<fetchPlan class="rest.sample.entity.Order"
extends="_base"
name="order-with-details">
<property name="customer"/>
<property name="lines" fetchPlan="_base">
<property name="product" fetchPlan="_instance_name" />
</property>
</fetchPlan>
</fetchPlans>
With that fetch plan configuration in place, you can perform the request and reference the fetch plan through the fetchPlan
URL parameter.
In the example below the Order with the ID 21021f78-edac-224b-e6f8-6e71e02a0f0d
is loaded with the fetch plan order-with-details
in order to additionally load customer
and lines
data:
GET http://localhost:8080/rest
/entities
/sample_Order
/21021f78-edac-224b-e6f8-6e71e02a0f0d
?fetchPlan=order-with-details
{
"id": "21021f78-edac-224b-e6f8-6e71e02a0f0d",
"date": "2020-12-13",
"amount": 49.99,
"lines": [ (1)
{
"id": "64e4fbb0-7fd6-818b-984e-a8769c4fbe88",
"product": {
"id": "7750adbe-6c30-cede-31a6-577a1a96aa83",
"name": "Outback Power Remote Power System"
},
"quantity": 1.0
}
],
"version": 1,
"customer": {
"id": "0826806e-6074-90fa-f241-564b5c94d018",
"name": "Sidney Chandler",
}
}
1 | The fetch plan order-with-details ensures that additional attributes like lines and customer are also included. |
Load List of Entities
You can load a list of entities of any type using the Load Entity List API endpoint: /entities/:entityName
. This API includes pagination, sorting, and fetch plans.
GET http://localhost:8080/rest/entities/sample_Customer
[
{
"id": "0826806e-6074-90fa-f241-564b5c94d018",
"name": "Sidney Chandler"
},
{
"id": "22efc597-69a9-aeef-4e4a-7afccd8e5767",
"name": "Randall Bishop"
},
{
"id": "bd1c8e90-3d35-cbe2-9efd-167202c758d2",
"name": "Shelby Robinson"
}
]
Every entity in the response has a _entityName attribute with the name of the entity, and an _instanceName attribute with the Instance Name of the entity.
|
It is also possible to further control the behavior of the API by using the following URL query parameters:
- fetchPlan
-
name of an entity’s fetch plan
(String)
. - limit
-
the number of entities to be returned by the API
(int)
. - offset
-
the position of the first returned entity
(int)
. - sort
-
an entity attribute that will be used for sorting
(String)
.-
+attribute
or simplyattribute
for ascending order -
-attribute
for descending order.
-
Using Sorting
The Load Entities API supports the sorting of the result by entity attributes. You can use the sort
URL parameter for controlling the order of entities.
When the sort parameter is not specified, the default sort order depends on the database implementation. Normally databases sort by the timestamp of record creation, but this behavior is not guaranteed and can vary in different situations.
|
Jmix has a special syntax to define the sort order. Ascending order is expressed through a +
before the attribute name. This is optional though, as it is the default behavior sorting order. For descending order, you need to prefix the entity attribute with a -
character.
The following example shows how you can sort Customers by their name
attribute ascending.
GET http://localhost:8080/rest
/entities
/sample_Customer
?sort=name
[
{
"id": "d83c9d66-cb23-075a-8d3c-d4035d338705",
"name": "Klaudia Kleinert"
},
{
"id": "8985ba1e-1cc8-eb5c-f9e0-738aee9d2ef1",
"name": "Randall Bishop"
}
]
You can also sort by multiple attributes. In this case, the sort order takes a comma-separated list of attributes to sort by.
GET http://localhost:8080/rest
/entities
/sample_Order?sort=+date,-amount
[
{
"id": "41aae331-b46b-85ee-b0bc-2de8cbf1ab86",
"date": "2021-02-02", (1)
"amount": 283.55
},
{
"id": "288a5d75-f06f-d150-9b70-efee1272b96c",
"date": "2021-03-01",
"amount": 249.99, (2)
"lastModifiedBy": "admin"
},
{
"id": "1068c217-5868-faf4-16aa-23655e9492da",
"date": "2021-03-01",
"amount": 130.08
}
]
1 | The result with the oldest date is returned first. |
2 | When the date attribute is the same, the amount is used to sort the results. |
Using Pagination
The Entities API supports Pagination to respect the data processing limitation that might be present on the server or client-side. In case you want to load only a particular subset of the entities, you can provide the offset
and limit
URL parameters.
Pagination is active by default, even if it is not explicitly requested by the client. In case no This default value is configurable globally via jmix.rest.default-max-fetch-size or on an entity-by-entity basis via jmix.rest.entityMaxFetchSize. |
The following example demonstrates how to load the third Page containing two Customer
entities (5. & 6. entity):
GET http://localhost:8080/rest
/entities
/sample_Customer
?limit=2
&offset=4
&sort=createdDate
[
{
"id": "2d620164-1e80-0696-c3aa-45b7b5c81f2c",
"name": "Maria Mitchell"
},
{
"id": "3c7ec69d-9b85-c6e9-387b-42a5bccb79de",
"name": "Anthony Knutson"
}
]
Load Entities via Search Filter
You can specify filter criteria when loading entities using the Entity Search Endpoint: /entities/:entityName/search
.
Both HTTP methods GET
and POST
are possible when interacting with the search endpoint. In both cases, the filter criterion has to be provided as part of the request.
The filter definition is a JSON structure that contains a set of conditions. A condition consists of the following attributes:
- property
-
the entity attribute that is being filtered on (like
amount
on the Order entity).In case the attribute is a reference to another entity, it can also be a property path like
customer.name
- operator
-
the filter operator. An operator describes how to filter for a particular attribute. There are multiple operators that can be used independently of the datatype:
-
Standard Operators:
=
,<>
,notEmpty
,isNull
-
List Operators:
in
,notIn
-
Additionally, some operators are only possible for particular datatypes:
Datatype | Specific Operators |
---|---|
String, UUID |
|
Integer, Long, Double, BigDecimal, Date, DateTime, Time, LocalDate, LocalDateTime, LocalTime, OffsetDateTime, OffsetTime |
|
- value
-
the value to search for. Value is not required for the
notEmpty
andisNull
operators.
Additionally, conditions can be combined via AND
, OR
group conditions to define a more complex filter criterion. The JSON structure of the filter definitions looks like this:
{
"conditions": [
{
"group": "OR",
"conditions": [
{
"property": "stringField",
"operator": "=",
"value": "stringValue"
},
{
"property": "intField",
"operator": ">",
"value": 100
}
]
},
{
"property": "booleanField",
"operator": "=",
"value": true
}
]
}
This is a representation of the Filter criterion: ((stringField = stringValue) OR (intField > 100) AND (booleanField = true))
.
When using the HTTP POST method, the filter is part of the request body.
POST http://localhost:8080/rest/entities/sample_Order/search
{
"filter": {
"conditions": [
{
"property": "customer.name",
"operator": "=",
"value": "Shelby Robinson"
}
]
}
}
When using the GET
method, the JSON filter criterion needs to be transferred via the URL Query parameter filter
.
GET http://localhost:8080/rest
/entities
/sample_Order
/search
?filter={"conditions":[{"property":"customer.name","operator":"contains","value":"Shelby"}]}
URI Encoding
The HTTP URI standard only allows ASCII characters as part of the URI / URL. When using URL Query parameters for the filter definition, the JSON definition has to be URL encoded to match this requirement. This is also true for the As there is also a practical limit of the URI length that can cause problems for big filter definitions, the |
Load Entities via JPQL
Another alternative to loading entities from the application is to use predefined JPQL queries. The Entity Query Endpoint /queries/:entityName/:queryName
is responsible for providing this capability. Queries can contain a list of parameters, that need to be provided by the client. Additionally, the endpoint contains the same general parameters for pagination, fetch plans, etc.
When to use JPQL vs. Search Filter?
Jmix provides various ways to load entity data generically. Use pre-defined JPQL queries when the search filter is not advanced enough to express the filter criterion. Also in case, the parameter should be pre-defined and not be adjustable by the API client. |
JPQL Query Configuration
To use the Entity Query endpoint you need to define the accessible queries. This happens via an XML configuration file, normally called rest-queries.xml
. You need to create this new file in your Jmix application under src/main/resources
. It lists all published queries with information about their parameters.
<?xml version="1.0"?>
<queries xmlns="http://jmix.io/schema/rest/queries">
<query name="ordersByDate" entity="sample_Order" fetchPlan="order-with-details">
<jpql><![CDATA[select e from sample_Order e where e.date = :orderDate]]></jpql>
<params>
<param name="orderDate" type="java.time.LocalDate"/>
</params>
</query>
<query name="ordersByCustomerName" entity="sample_Order" fetchPlan="order-with-details">
<jpql><![CDATA[select e from sample_Order e where e.customer.name = :customerName]]></jpql>
<params>
<param name="customerName" type="java.lang.String"/>
</params>
</query>
</queries>
A query needs to have a unique name
value as well as an entity
reference. The combination of name
and entity
needs to be unique. Also, a fetchPlan
needs to be referenced to indicate which entity attributes are returned.
In the <jpql>
tag the actual query is configured. The parameters need to be listed within the params
tag defining their name and Java type. In the query parameters, you can reference via their name prefixed with a colon like :customerName
.
After the file has been created, and the queries have been defined, you need to register the rest-queries.xml
configuration in the application.properties
of your Jmix application:
jmix.rest.queries-config = rest/sample/rest-queries.xml
You can invoke the Entity Query endpoint either by the GET
or POST
HTTP method. In the case of GET
, the parameters are appended as URL query parameters.
GET http://localhost:8080/rest
/queries
/sample_Order
/ordersByDate
?orderDate=2020-02-02
URI Encoding
The URL should only contain ASCII characters. This means the values of the parameters need to be URL encoded, as those values normally represent direct user input and therefore it cannot be ensured that non-ASCII characters are used. |
In the case of using POST
, the query parameters are transferred in the JSON body containing each parameter as a key.
POST http://localhost:8080/rest/queries/sample_Order/ordersByCustomerName
{
"customerName": "Shelby Robinson"
}
Collection Parameters
It is also possible to define a parameter as a collection type. In this case, the query definition should contain an []
indicator after the Java type.
<?xml version="1.0"?>
<queries xmlns="http://jmix.io/schema/rest/queries">
<query name="ordersByIds" entity="sample_Order" fetchPlan="order-with-details">
<jpql><![CDATA[select e from sample_Order e where e.id in :ids]]></jpql>
<params>
<param name="ids" type="java.util.UUID[]"/> (1)
</params>
</query>
</queries>
1 | The ids parameter is marked as collection of UUID type. |
When this parameter is used in a query, the corresponding IDs have to be provided as a JSON array.
POST http://localhost:8080/rest/queries/sample_Order/ordersByIds
{
"ids": [
"41aae331-b46b-85ee-b0bc-2de8cbf1ab86",
"21021f78-edac-224b-e6f8-6e71e02a0f0d"
]
}
Return Empty Values in JSON
By default, Jmix will remove empty values (null
) from the JSON response, so that the attribute keys are not present in the JSON document.
You can control this behavior by using the URL query parameter returnNulls
and set its value to true
. With that, Jmix will always add the attribute keys to the response, independent if the value is empty or not.
In the following example, a Customer is loaded by its ID and also requesting to contain all empty values:
GET http://localhost:8080/rest
/entities
/sample_Customer
/1eab4973-25f9-70d9-5356-6990dd8f79e2
?returnNulls=true
{
"_entityName": "sample_Customer",
"_instanceName": "Sidney Chandler",
"id": "0826806e-6074-90fa-f241-564b5c94d018",
"createdDate": "2021-06-09T08:42:39.291",
"createdBy": "admin",
"lastModifiedDate": "2021-06-09T08:42:39.291",
"deletedDate": null,
"lastModifiedBy": null,
"name": "Sidney Chandler",
"type": null, (1)
"version": 1,
"deletedBy": null
}
1 | The response contains the key type although it is empty |
The Parameter returnNulls is present in all Entity Load APIs: Load by ID, Load List, Search and Load by Query.
|