Add GET action, and usage in API

This commit is contained in:
2022-10-21 14:36:23 -05:00
parent 204d67dd21
commit f5f6446069
14 changed files with 743 additions and 50 deletions

View File

@ -24,6 +24,7 @@ package com.kingsrook.qqq.backend.module.api;
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.DeleteInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.InsertInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
@ -31,6 +32,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableBackendDetails;
import com.kingsrook.qqq.backend.core.modules.backend.QBackendModuleInterface;
import com.kingsrook.qqq.backend.module.api.actions.APICountAction;
import com.kingsrook.qqq.backend.module.api.actions.APIGetAction;
import com.kingsrook.qqq.backend.module.api.actions.APIInsertAction;
import com.kingsrook.qqq.backend.module.api.actions.APIQueryAction;
@ -94,6 +96,17 @@ public class APIBackendModule implements QBackendModuleInterface
/*******************************************************************************
**
*******************************************************************************/
@Override
public GetInterface getGetInterface()
{
return (new APIGetAction());
}
/*******************************************************************************
**
*******************************************************************************/

View File

@ -58,7 +58,7 @@ public class APICountAction extends AbstractAPIAction implements CountInterface
try
{
QQueryFilter filter = countInput.getFilter();
String paramString = apiActionUtil.buildQueryString(filter, null, null, table.getFields());
String paramString = apiActionUtil.buildQueryStringForGet(filter, null, null, table.getFields());
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
HttpClient client = httpClientBuilder.build();

View File

@ -0,0 +1,83 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.kingsrook.qqq.backend.module.api.actions;
import com.kingsrook.qqq.backend.core.actions.interfaces.GetInterface;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.get.GetOutput;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/*******************************************************************************
**
*******************************************************************************/
public class APIGetAction extends AbstractAPIAction implements GetInterface
{
private static final Logger LOG = LogManager.getLogger(APIGetAction.class);
/*******************************************************************************
**
*******************************************************************************/
public GetOutput execute(GetInput getInput) throws QException
{
QTableMetaData table = getInput.getTable();
preAction(getInput);
try
{
String urlSuffix = apiActionUtil.buildUrlSuffixForSingleRecordGet(getInput.getPrimaryKey());
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
HttpClient client = httpClientBuilder.build();
String url = apiActionUtil.buildTableUrl(table);
HttpGet request = new HttpGet(url + urlSuffix);
apiActionUtil.setupAuthorizationInRequest(request);
apiActionUtil.setupContentTypeInRequest(request);
apiActionUtil.setupAdditionalHeaders(request);
HttpResponse response = client.execute(request);
QRecord record = apiActionUtil.processSingleRecordGetResponse(table, response);
GetOutput rs = new GetOutput();
rs.setRecord(record);
return rs;
}
catch(Exception e)
{
LOG.warn("Error in API get", e);
throw new QException("Error executing get: " + e.getMessage(), e);
}
}
}

View File

@ -58,7 +58,7 @@ public class APIQueryAction extends AbstractAPIAction implements QueryInterface
try
{
QQueryFilter filter = queryInput.getFilter();
String paramString = apiActionUtil.buildQueryString(filter, queryInput.getLimit(), queryInput.getSkip(), table.getFields());
String paramString = apiActionUtil.buildQueryStringForGet(filter, queryInput.getLimit(), queryInput.getSkip(), table.getFields());
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
HttpClient client = httpClientBuilder.build();

View File

@ -32,14 +32,16 @@ import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.model.actions.AbstractTableActionInput;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QCriteriaOperator;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QFilterCriteria;
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.CollectionUtils;
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.ValueUtils;
import com.kingsrook.qqq.backend.module.api.model.metadata.APIBackendMetaData;
import com.kingsrook.qqq.backend.module.api.model.metadata.APITableBackendDetails;
import org.apache.http.HttpEntity;
@ -101,7 +103,7 @@ public class BaseAPIActionUtil
** method to build up a query string based on a given QFilter object
**
*******************************************************************************/
protected String buildQueryString(QQueryFilter filter, Integer limit, Integer skip, Map<String, QFieldMetaData> fields) throws QException
protected String buildQueryStringForGet(QQueryFilter filter, Integer limit, Integer skip, Map<String, QFieldMetaData> fields) throws QException
{
// todo: reasonable default action
return (null);
@ -109,6 +111,19 @@ public class BaseAPIActionUtil
/*******************************************************************************
** Do a default query string for a single-record GET - e.g., a query for just 1 record.
*******************************************************************************/
public String buildUrlSuffixForSingleRecordGet(Serializable primaryKey) throws QException
{
QTableMetaData table = actionInput.getTable();
QQueryFilter filter = new QQueryFilter()
.withCriteria(new QFilterCriteria(table.getPrimaryKeyField(), QCriteriaOperator.EQUALS, List.of(primaryKey)));
return (buildQueryStringForGet(filter, 1, 0, table.getFields()));
}
/*******************************************************************************
** As part of making a request - set up its authorization header (not just
** strictly "Authorization", but whatever is needed for auth).
@ -308,14 +323,7 @@ public class BaseAPIActionUtil
*******************************************************************************/
protected QRecord processPostResponse(QTableMetaData table, QRecord record, HttpResponse response) throws IOException
{
int statusCode = response.getStatusLine().getStatusCode();
LOG.debug(statusCode);
HttpEntity entity = response.getEntity();
String resultString = EntityUtils.toString(entity);
LOG.debug(resultString);
JSONObject jsonObject = JsonUtils.toJSONObject(resultString);
JSONObject jsonObject = getJsonObject(response);
String primaryKeyFieldName = table.getPrimaryKeyField();
String primaryKeyBackendName = getFieldBackendName(table.getField(primaryKeyFieldName));
@ -346,6 +354,24 @@ public class BaseAPIActionUtil
/*******************************************************************************
**
*******************************************************************************/
private JSONObject getJsonObject(HttpResponse response) throws IOException
{
int statusCode = response.getStatusLine().getStatusCode();
LOG.debug(statusCode);
HttpEntity entity = response.getEntity();
String resultString = EntityUtils.toString(entity);
LOG.debug(resultString);
JSONObject jsonObject = JsonUtils.toJSONObject(resultString);
return jsonObject;
}
/*******************************************************************************
**
*******************************************************************************/
@ -418,8 +444,18 @@ public class BaseAPIActionUtil
/*******************************************************************************
**
*******************************************************************************/
protected String urlEncode(String s)
protected String urlEncode(Serializable s)
{
return (URLEncoder.encode(s, StandardCharsets.UTF_8));
return (URLEncoder.encode(ValueUtils.getValueAsString(s), StandardCharsets.UTF_8));
}
/*******************************************************************************
**
*******************************************************************************/
public QRecord processSingleRecordGetResponse(QTableMetaData table, HttpResponse response) throws IOException
{
return (jsonObjectToRecord(getJsonObject(response), table.getFields()));
}
}