Issue
I am trying to use the com.gluonhq.connect.provider.RestClient to query an API that is Elastic Search enabled.
Maven:
<dependency>
<groupId>com.gluonhq</groupId>
<artifactId>connect</artifactId>
<version>2.0.1</version>
</dependency>
I have attempted to make a request using the following:
private GluonObservableObject<Item> getData() {
RestClient myApiClient = RestClient.create()
.method("POST")
.host(applicationProperties.getAPIURL())
.path("search")
.header("accept", "application/json")
.header("Content-type", "application/json")
.queryParam("private_key", applicationProperties.getAPIKEY())
.dataString(ITEMREQUEST);
return DataProvider.retrieveObject(
myApiClient.createObjectDataReader(Item.class));
}
...where the dataString is a json-formatted String representing the body of the request (I can assume the request is correctly formatted because I tested it in Postman and the request returned the expected data). If it helps, here is the elasticsearch request body:
{
"indexes": "idx1, idx2",
"columns": "col1,col2,col3,col4,col5",
"body": {
"query": {
"bool": {
"must": [
{
"wildcard": {
"NameCombined_en": "*"
}
}
],
"filter": [
{
"range": {
"ID": {
"gte": "20000"
}
}
}
]
}
},
"from": 0,
"size": 100
}
}
The problem I have is that the (gluon) RestClient and, by extension, the DataProvider.retrieveObject method return exactly...nothing.
I'm pretty sure I'm doing something wrong and I'm fairly certain it is the .dataString() method (which requires an "entity"), but I have not found an alternative to use as a way of passing the body into the request.
The reasoning behind using the com.gluonhq.connect library is to avoid having to also create my own Observable lists (by hand) - the library automatically spits one out, providing the data is suitably formatted...and present. At least, that's my understanding of it.
Can someone point me in the right direction? I have found no indication or explanation of how to do POST requests with this library.
UPDATE 20220117
Main.java
public class Main extends Application {
ApplicationProperties applicationProperties = new ApplicationProperties();
private static final String RESTLIST_VIEW = HOME_VIEW;
private static final String RESTOBJECT_VIEW = "RestObjectView";
private final AppManager appManager = AppManager.initialize(this::postInit);
@Override
public void init() {
appManager.addViewFactory(RESTOBJECT_VIEW, () -> new RestObjectView(applicationProperties.APIURL, applicationProperties.APIKEY));
updateDrawer();
}
@Override
public void start(Stage stage) {
appManager.start(stage);
}
private void postInit(Scene scene) {
Swatch.BLUE.assignTo(scene);
((Stage) scene.getWindow()).getIcons().add(new Image(Objects.requireNonNull(Main.class.getResourceAsStream("/icon.png"))));
}
private void updateDrawer() {
NavigationDrawer navigationDrawer = appManager.getDrawer();
NavigationDrawer.Header header = new NavigationDrawer.Header("Gluon Mobile", "Gluon Connect Rest Provider Sample",
new Avatar(21, new Image(getClass().getResourceAsStream("/icon.png"))));
navigationDrawer.setHeader(header);
NavigationDrawer.Item listItem = new NavigationDrawer.Item("List Viewer", MaterialDesignIcon.VIEW_LIST.graphic());
NavigationDrawer.Item objectItem = new NavigationDrawer.Item("Object Viewer", MaterialDesignIcon.INSERT_DRIVE_FILE.graphic());
navigationDrawer.getItems().addAll(listItem, objectItem);
navigationDrawer.selectedItemProperty().addListener((obs, oldItem, newItem) -> {
if (newItem.equals(listItem)) {
appManager.switchView(RESTLIST_VIEW);
} else if (newItem.equals(objectItem)) {
appManager.switchView(RESTOBJECT_VIEW);
}
});
}
public static void main(String[] args) {
System.setProperty("javafx.platform", "Desktop");
launch(args);
}
RestObjectView.java
public class RestObjectView extends View {
public RestObjectView(String apiurl, String apikey) {
Label lbItemId = new Label();
Label lbName = new Label();
Label lbDescription = new Label();
Label lbLvlItem = new Label();
Label lbLvlEquip = new Label();
GridPane gridPane = new GridPane();
gridPane.setVgap(5.0);
gridPane.setHgap(5.0);
gridPane.setPadding(new Insets(5.0));
gridPane.addRow(0, new Label("Item ID:"), lbItemId);
gridPane.addRow(1, new Label("Name:"), lbName);
gridPane.addRow(2, new Label("Description:"), lbDescription);
gridPane.addRow(3, new Label("Item Level:"), lbLvlItem);
gridPane.addRow(4, new Label("Equip Level:"), lbLvlEquip);
gridPane.getColumnConstraints().add(new ColumnConstraints(75));
lbItemId.setWrapText(true);
lbName.setWrapText(true);
lbDescription.setWrapText(true);
lbLvlItem.setWrapText(false);
lbLvlEquip.setWrapText(false);
setCenter(gridPane);
// create a RestClient to the specific URL
RestClient restClient = RestClient.create()
.method("POST")
.host(apiurl)
.path("Item")
.queryParam("private_key", apikey);
// create a custom Converter that is able to parse the response into a single object
InputStreamInputConverter<Item> converter = new SingleItemInputConverter<>(Item.class);
// retrieve an object from the DataProvider
GluonObservableObject<Item> item = DataProvider.retrieveObject(restClient.createObjectDataReader(converter));
// when the object is initialized, bind its properties to the JavaFX UI controls
item.initializedProperty().addListener((obs, oldValue, newValue) -> {
if (newValue) {
lbItemId.textProperty().bind(item.get().itemIdProperty().asString());
lbName.textProperty().bind(item.get().nameProperty());
lbDescription.textProperty().bind(item.get().descriptionProperty());
lbLvlItem.textProperty().bind(item.get().levelItemProperty().asString());
lbLvlEquip.textProperty().bind(item.get().levelEquipProperty().asString());
}
});
}
@Override
protected void updateAppBar(AppBar appBar) {
appBar.setNavIcon(MaterialDesignIcon.MENU.button(e -> getAppManager().getDrawer().open()));
appBar.setTitleText("Rest Object Viewer");
}
}
Solution
This is a quick demo of RestClient
with GET
and POST
:
ToDoItem
class:
public class ToDoItem {
private int userId;
private int id;
private String title;
private boolean completed;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
@Override
public String toString() {
return "ToDoItem{" +
"userId=" + userId +
", id=" + id +
", title='" + title + '\'' +
", completed=" + completed +
'}';
}
}
GET
test:
public void getTest() {
RestClient restClient = RestClient.create()
.method("GET")
.host("http://jsonplaceholder.typicode.com")
.path("/todos/1");
GluonObservableObject<ToDoItem> singleToDoItem =
DataProvider.retrieveObject(
restClient.createObjectDataReader(ToDoItem.class));
singleToDoItem.setOnSucceeded(e ->
System.out.println("ToDoItem successfully retrieved: " + singleToDoItem.get()));
singleToDoItem.setOnFailed(e -> {
System.out.println("ToDoItem GET error");
if (singleToDoItem.getException() != null) {
singleToDoItem.getException().printStackTrace();
}
});
}
POST
test:
public void postTest() {
ToDoItem toDoItem = new ToDoItem();
toDoItem.setCompleted(Math.random() > 0.5);
toDoItem.setTitle(UUID.randomUUID().toString());
toDoItem.setUserId(1);
// write a new todo item to a rest source
RestClient restClient = RestClient.create()
.method("POST")
.contentType("application/json")
.host("http://jsonplaceholder.typicode.com")
.path("/todos");
GluonObservableObject<ToDoItem> obsToDoItem =
DataProvider.storeObject(toDoItem,
restClient.createObjectDataWriter(ToDoItem.class));
obsToDoItem.setOnSucceeded(e ->
System.out.println("ToDoItem successfully written: " + obsToDoItem.get()));
obsToDoItem.setOnFailed(e -> {
System.out.println("ToDoItem POST error");
if (obsToDoItem.getException() != null) {
obsToDoItem.getException().printStackTrace();
}
});
}
Running both should give you something like this:
ToDoItem successfully retrieved: ToDoItem{userId=1, id=1, title='delectus aut autem', completed=false}
ToDoItem successfully written: ToDoItem{userId=1, id=201, title='6977035b-7a0c-4e6a-82e5-141b414db92a', completed=false}
Answered By - José Pereda
Answer Checked By - Clifford M. (JavaFixing Volunteer)