mirror of
https://github.com/Kingsrook/qqq.git
synced 2025-07-18 13:10:44 +00:00
updated api backend to support count and query
This commit is contained in:
@ -30,15 +30,9 @@ import com.kingsrook.qqq.backend.core.actions.interfaces.UpdateInterface;
|
||||
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.APIInsertAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSCountAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSDeleteAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSInsertAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSQueryAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.actions.RDBMSUpdateAction;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSBackendMetaData;
|
||||
// import com.kingsrook.qqq.backend.module.rdbms.model.metadata.RDBMSTableBackendDetails;
|
||||
|
||||
import com.kingsrook.qqq.backend.module.api.actions.APIQueryAction;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
@ -84,7 +78,7 @@ public class APIBackendModule implements QBackendModuleInterface
|
||||
@Override
|
||||
public CountInterface getCountInterface()
|
||||
{
|
||||
return (null); //return (new RDBMSCountAction());
|
||||
return (new APICountAction());
|
||||
}
|
||||
|
||||
|
||||
@ -95,7 +89,7 @@ public class APIBackendModule implements QBackendModuleInterface
|
||||
@Override
|
||||
public QueryInterface getQueryInterface()
|
||||
{
|
||||
return (null); //return (new RDBMSQueryAction());
|
||||
return (new APIQueryAction());
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.CountInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.count.CountOutput;
|
||||
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.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 APICountAction extends AbstractAPIAction implements CountInterface
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(APICountAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public CountOutput execute(CountInput countInput) throws QException
|
||||
{
|
||||
QTableMetaData table = countInput.getTable();
|
||||
preAction(countInput);
|
||||
|
||||
try
|
||||
{
|
||||
QQueryFilter filter = countInput.getFilter();
|
||||
String paramString = apiActionUtil.buildQueryString(filter, null, null, table.getFields());
|
||||
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||
HttpClient client = httpClientBuilder.build();
|
||||
|
||||
String url = apiActionUtil.buildTableUrl(table);
|
||||
HttpGet request = new HttpGet(url + paramString);
|
||||
|
||||
apiActionUtil.setupAuthorizationInRequest(request);
|
||||
apiActionUtil.setupContentTypeInRequest(request);
|
||||
apiActionUtil.setupAdditionalHeaders(request);
|
||||
|
||||
HttpResponse response = client.execute(request);
|
||||
List<QRecord> queryResults = apiActionUtil.processGetResponse(table, response);
|
||||
|
||||
CountOutput rs = new CountOutput();
|
||||
rs.setCount(queryResults.size());
|
||||
return rs;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error in API count", e);
|
||||
throw new QException("Error executing count: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* 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 java.util.List;
|
||||
import com.kingsrook.qqq.backend.core.actions.interfaces.QueryInterface;
|
||||
import com.kingsrook.qqq.backend.core.exceptions.QException;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QQueryFilter;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryInput;
|
||||
import com.kingsrook.qqq.backend.core.model.actions.tables.query.QueryOutput;
|
||||
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 APIQueryAction extends AbstractAPIAction implements QueryInterface
|
||||
{
|
||||
private static final Logger LOG = LogManager.getLogger(APIQueryAction.class);
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
public QueryOutput execute(QueryInput queryInput) throws QException
|
||||
{
|
||||
QTableMetaData table = queryInput.getTable();
|
||||
preAction(queryInput);
|
||||
|
||||
try
|
||||
{
|
||||
QQueryFilter filter = queryInput.getFilter();
|
||||
String paramString = apiActionUtil.buildQueryString(filter, queryInput.getLimit(), queryInput.getSkip(), table.getFields());
|
||||
|
||||
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
|
||||
HttpClient client = httpClientBuilder.build();
|
||||
|
||||
String url = apiActionUtil.buildTableUrl(table) + paramString;
|
||||
HttpGet request = new HttpGet(url);
|
||||
|
||||
LOG.info("API URL: " + url);
|
||||
|
||||
apiActionUtil.setupAuthorizationInRequest(request);
|
||||
apiActionUtil.setupContentTypeInRequest(request);
|
||||
apiActionUtil.setupAdditionalHeaders(request);
|
||||
|
||||
HttpResponse response = client.execute(request);
|
||||
List<QRecord> queryResults = apiActionUtil.processGetResponse(table, response);
|
||||
|
||||
QueryOutput queryOutput = new QueryOutput(queryInput);
|
||||
queryOutput.addRecords(queryResults);
|
||||
return (queryOutput);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
LOG.warn("Error in API Query", e);
|
||||
throw new QException("Error executing query: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -24,10 +24,17 @@ package com.kingsrook.qqq.backend.module.api.actions;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
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.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;
|
||||
@ -43,6 +50,7 @@ import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.util.EntityUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
|
||||
|
||||
@ -89,6 +97,18 @@ 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
|
||||
{
|
||||
// todo: reasonable default action
|
||||
return (null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
** As part of making a request - set up its authorization header (not just
|
||||
** strictly "Authorization", but whatever is needed for auth).
|
||||
@ -107,6 +127,10 @@ public class BaseAPIActionUtil
|
||||
request.addHeader("Authorization", getBasicAuthenticationHeader(backendMetaData.getUsername(), backendMetaData.getPassword()));
|
||||
break;
|
||||
|
||||
case API_KEY_HEADER:
|
||||
request.addHeader("API-Key", backendMetaData.getApiKey());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unexpected authorization type: " + backendMetaData.getAuthorizationType());
|
||||
}
|
||||
@ -141,7 +165,7 @@ public class BaseAPIActionUtil
|
||||
*******************************************************************************/
|
||||
public void setupAdditionalHeaders(HttpRequestBase request)
|
||||
{
|
||||
|
||||
request.addHeader("Accept", "application/json");
|
||||
}
|
||||
|
||||
|
||||
@ -219,6 +243,66 @@ public class BaseAPIActionUtil
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected QRecord jsonObjectToRecord(JSONObject jsonObject, Map<String, QFieldMetaData> fields) throws IOException
|
||||
{
|
||||
QRecord record = JsonUtils.parseQRecord(jsonObject, fields);
|
||||
return (record);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected List<QRecord> processGetResponse(QTableMetaData table, HttpResponse response) throws IOException
|
||||
{
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
System.out.println(statusCode);
|
||||
|
||||
HttpEntity entity = response.getEntity();
|
||||
String resultString = EntityUtils.toString(entity);
|
||||
|
||||
List<QRecord> recordList = new ArrayList<>();
|
||||
if(StringUtils.hasContent(resultString))
|
||||
{
|
||||
JSONArray resultList = null;
|
||||
JSONObject jsonObject = null;
|
||||
|
||||
if(resultString.startsWith("["))
|
||||
{
|
||||
resultList = JsonUtils.toJSONArray(resultString);
|
||||
}
|
||||
else
|
||||
{
|
||||
String tablePath = getBackendDetails(table).getTablePath();
|
||||
jsonObject = JsonUtils.toJSONObject(resultString);
|
||||
if(jsonObject.has(tablePath))
|
||||
{
|
||||
resultList = jsonObject.getJSONArray(getBackendDetails(table).getTablePath());
|
||||
}
|
||||
}
|
||||
|
||||
if(resultList != null)
|
||||
{
|
||||
for(int i = 0; i < resultList.length(); i++)
|
||||
{
|
||||
recordList.add(jsonObjectToRecord(resultList.getJSONObject(i), table.getFields()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
recordList.add(jsonObjectToRecord(jsonObject, table.getFields()));
|
||||
}
|
||||
}
|
||||
|
||||
return (recordList);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
@ -328,4 +412,14 @@ public class BaseAPIActionUtil
|
||||
{
|
||||
this.actionInput = actionInput;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
**
|
||||
*******************************************************************************/
|
||||
protected String urlEncode(String s)
|
||||
{
|
||||
return (URLEncoder.encode(s, StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ package com.kingsrook.qqq.backend.module.api.model;
|
||||
*******************************************************************************/
|
||||
public enum AuthorizationType
|
||||
{
|
||||
API_KEY_HEADER,
|
||||
BASIC_AUTH_API_KEY,
|
||||
BASIC_AUTH_USERNAME_PASSWORD
|
||||
BASIC_AUTH_USERNAME_PASSWORD,
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user