Initial checkin of qqq-middleware-api

This commit is contained in:
2023-03-20 14:31:23 -05:00
parent d6a9c8f0e0
commit d0e8bd9db2
44 changed files with 9730 additions and 1 deletions

View File

@ -37,9 +37,10 @@
<module>qqq-middleware-picocli</module>
<module>qqq-middleware-javalin</module>
<module>qqq-middleware-lambda</module>
<module>qqq-middleware-slack</module>
<module>qqq-middleware-api</module>
<module>qqq-utility-lambdas</module>
<module>qqq-sample-project</module>
<module>qqq-middleware-slack</module>
</modules>
<properties>

View File

@ -6,4 +6,5 @@ qqq-language-support-javascript
qqq-middleware-javalin
qqq-middleware-picocli
qqq-middleware-slack
qqq-middleware-api
qqq-frontend-material-dashboard

View File

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ QQQ - Low-code Application Framework for Engineers.
~ Copyright (C) 2021-2023. 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/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>qqq-middleware-api</artifactId>
<parent>
<groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-parent-project</artifactId>
<version>${revision}</version>
</parent>
<properties>
<!-- props specifically to this module -->
<!-- none at this time -->
</properties>
<dependencies>
<!-- other qqq modules deps -->
<dependency>
<groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-backend-core</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>com.kingsrook.qqq</groupId>
<artifactId>qqq-middleware-javalin</artifactId>
<version>${revision}</version>
</dependency>
<!-- 3rd party deps specifically for this module -->
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>5.1.4</version>
</dependency>
<dependency>
<groupId>com.konghq</groupId>
<artifactId>unirest-java</artifactId>
<version>3.13.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.36</version>
</dependency>
<!-- Common deps for all qqq modules -->
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,66 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api;
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
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;
/*******************************************************************************
**
*******************************************************************************/
public interface ApiMiddlewareType
{
String NAME = "api";
/*******************************************************************************
**
*******************************************************************************/
static ApiInstanceMetaData getApiInstanceMetaData(QInstance instance)
{
return ((ApiInstanceMetaData) instance.getMiddlewareMetaData(NAME));
}
/*******************************************************************************
**
*******************************************************************************/
static ApiTableMetaData getApiTableMetaData(QTableMetaData table)
{
return ((ApiTableMetaData) table.getMiddlewareMetaData(NAME));
}
/*******************************************************************************
**
*******************************************************************************/
static ApiFieldMetaData getApiFieldMetaData(QFieldMetaData field)
{
return ((ApiFieldMetaData) field.getMiddlewareMetaData(NAME));
}
}

View File

@ -0,0 +1,555 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.actions;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
import com.kingsrook.qqq.api.model.openapi.Components;
import com.kingsrook.qqq.api.model.openapi.Contact;
import com.kingsrook.qqq.api.model.openapi.Content;
import com.kingsrook.qqq.api.model.openapi.Example;
import com.kingsrook.qqq.api.model.openapi.ExampleWithListValue;
import com.kingsrook.qqq.api.model.openapi.ExampleWithSingleValue;
import com.kingsrook.qqq.api.model.openapi.Info;
import com.kingsrook.qqq.api.model.openapi.Method;
import com.kingsrook.qqq.api.model.openapi.OpenAPI;
import com.kingsrook.qqq.api.model.openapi.Parameter;
import com.kingsrook.qqq.api.model.openapi.Path;
import com.kingsrook.qqq.api.model.openapi.Response;
import com.kingsrook.qqq.api.model.openapi.Schema;
import com.kingsrook.qqq.api.model.openapi.Server;
import com.kingsrook.qqq.api.model.openapi.Tag;
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
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.fields.QFieldType;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.core.utils.YamlUtils;
import com.kingsrook.qqq.backend.core.utils.collections.ListBuilder;
import com.kingsrook.qqq.backend.core.utils.collections.MapBuilder;
/*******************************************************************************
**
*******************************************************************************/
public class GenerateOpenApiSpecAction extends AbstractQActionFunction<GenerateOpenApiSpecInput, GenerateOpenApiSpecOutput>
{
/*******************************************************************************
**
*******************************************************************************/
public GenerateOpenApiSpecOutput execute(GenerateOpenApiSpecInput input) throws QException
{
String version = input.getVersion();
QInstance qInstance = QContext.getQInstance();
OpenAPI openAPI = new OpenAPI()
.withVersion("3.0.3")
.withInfo(new Info()
.withTitle("QQQ API")
.withDescription("This is an openAPI built by QQQ")
.withContact(new Contact()
.withEmail("contact@kingsrook.com")
)
.withVersion(version)
)
.withServers(ListBuilder.of(new Server()
.withDescription("Localhost development")
.withUrl("http://localhost:8000/api")
));
openAPI.setTags(new ArrayList<>());
openAPI.setPaths(new LinkedHashMap<>());
LinkedHashMap<Integer, Response> componentResponses = new LinkedHashMap<>();
LinkedHashMap<String, Schema> componentSchemas = new LinkedHashMap<>();
openAPI.setComponents(new Components()
.withSchemas(componentSchemas)
.withResponses(componentResponses)
);
componentSchemas.put("baseSearchResultFields", new Schema()
.withType("object")
.withProperties(MapBuilder.of(
"count", new Schema()
.withType("integer")
.withDescription("Number of records that matched the search criteria"),
"pageNo", new Schema()
.withType("integer")
.withDescription("Requested result page number"),
"pageSize", new Schema()
.withType("integer")
.withDescription("Requested result page size")
))
);
///////////////////
// foreach table //
///////////////////
for(QTableMetaData table : qInstance.getTables().values())
{
String tableName = table.getName();
String tableNameUcFirst = StringUtils.ucFirst(table.getName());
String tableLabel = table.getLabel();
String primaryKeyName = table.getPrimaryKeyField();
String primaryKeyLabel = table.getField(table.getPrimaryKeyField()).getLabel();
List<? extends QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
////////////////////////
// tag for this table //
////////////////////////
openAPI.getTags().add(new Tag()
.withName(tableLabel)
.withDescription("Operations on the " + tableLabel + " table."));
//////////////////////////////////////
// build the schemas for this table //
//////////////////////////////////////
LinkedHashMap<String, Schema> tableFieldsWithoutPrimaryKey = new LinkedHashMap<>();
componentSchemas.put(tableName + "WithoutPrimaryKey", new Schema()
.withType("object")
.withProperties(tableFieldsWithoutPrimaryKey));
for(QFieldMetaData tableApiField : tableApiFields)
{
tableFieldsWithoutPrimaryKey.put(tableApiField.getName(), new Schema()
.withType(getFieldType(table.getField(tableApiField.getName())))
.withDescription(tableApiField.getLabel() + " for the " + tableLabel + ".")
);
}
componentSchemas.put(tableName, new Schema()
.withType("object")
.withAllOf(ListBuilder.of(new Schema().withRef("#/components/schemas/" + tableName + "WithoutPrimaryKey")))
.withProperties(MapBuilder.of(
primaryKeyName, new Schema()
.withType(getFieldType(table.getField(primaryKeyName)))
.withDescription(primaryKeyLabel + " for the " + tableLabel + ". Primary Key.")
))
);
componentSchemas.put(tableName + "SearchResult", new Schema()
.withType("object")
.withAllOf(ListBuilder.of(new Schema().withRef("#/components/schemas/baseSearchResultFields")))
.withProperties(MapBuilder.of(
"records", new Schema()
.withType("array")
.withItems(new Schema()
.withAllOf(ListBuilder.of(
new Schema().withRef("#/components/schemas/" + tableName),
new Schema().withRef("#/components/schemas/" + tableName + "WithoutPrimaryKey")
))
)
))
);
//////////////////////////////////////
// paths and methods for this table //
//////////////////////////////////////
Method queryGet = new Method()
.withSummary("Search the " + tableLabel + " table using multiple query string fields.")
.withDescription("TODO")
.withOperationId("query" + tableNameUcFirst)
.withTags(ListBuilder.of(tableLabel))
.withParameters(ListBuilder.of(
new Parameter()
.withName("pageNo")
.withDescription("Which page of results to return. Starts at 1.")
.withIn("query")
.withSchema(new Schema().withType("integer")),
new Parameter()
.withName("pageSize")
.withDescription("Max number of records to include in a page. Defaults to 50.")
.withIn("query")
.withSchema(new Schema().withType("integer")),
new Parameter()
.withName("includeCount")
.withDescription("Whether or not to include the count (total matching records) in the result. Default is true.")
.withIn("query")
.withSchema(new Schema().withType("boolean")),
new Parameter()
.withName("orderBy")
.withDescription("""
How the results of the query should be sorted.<br/>
SQL-style, comma-separated list of field names, each optionally followed by ASC or DESC (defaults to ASC).
""")
.withIn("query")
.withSchema(new Schema().withType("string"))
.withExamples(buildOrderByExamples(primaryKeyName, tableApiFields)),
new Parameter()
.withName("booleanOperator")
.withDescription("Whether to combine query field as an AND or an OR. Default is AND.")
.withIn("query")
.withSchema(new Schema().withType("string").withEnumValues(ListBuilder.of("AND", "OR")))
))
.withResponses(buildStandardErrorResponses())
.withResponse(200, new Response()
.withDescription("Successfully searched the " + tableLabel + " table (though may have found 0 records).")
.withContent(MapBuilder.of("application/json", new Content()
.withSchema(new Schema().withRef("#/components/schemas/" + tableName + "SearchResult"))
))
);
for(QFieldMetaData tableApiField : tableApiFields)
{
queryGet.getParameters().add(new Parameter()
.withName(tableApiField.getName())
.withDescription("Query on the " + tableApiField.getLabel() + " field. Can prefix value with an operator, else defaults to = (equals).")
.withIn("query")
.withExplode(true)
.withSchema(new Schema()
.withType("array")
.withItems(new Schema().withType("string")))
.withExamples(MapBuilder.of(
// todo - multiple examples, and different per-type, and as components
"notQueried", new ExampleWithListValue().withSummary("no query on this field").withValue(ListBuilder.of("")),
"equals", new ExampleWithListValue().withSummary("equal to 47").withValue(ListBuilder.of("47")),
"complex", new ExampleWithListValue().withSummary("between 42 and 47 and not equal to 45").withValue(ListBuilder.of("BETWEEN 42,47", "!=45"))
))
);
}
openAPI.getPaths().put("/" + tableName + "/query", new Path().withGet(queryGet)
/*
.withPost(new Method()
.withSummary("Search the " + tableLabel + " table by posting a QueryFilter object.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
*/
);
/*
openAPI.getPaths().put("/" + tableName + "/{" + primaryKeyName + "}", new Path()
.withGet(new Method()
.withSummary("Get one " + tableLabel + " record by " + primaryKeyLabel + ".")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
.withPatch(new Method()
.withSummary("Update one " + tableLabel + " record.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
.withDelete(new Method()
.withSummary("Delete one " + tableLabel + " record.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
);
openAPI.getPaths().put("/" + tableName, new Path()
.withPost(new Method()
.withSummary("Create one " + tableLabel + " record.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
);
openAPI.getPaths().put("/" + tableName + "/bulk", new Path()
.withPatch(new Method()
.withSummary("Update multiple " + tableLabel + " records.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
.withDelete(new Method()
.withSummary("Delete multiple " + tableLabel + " records.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
.withPost(new Method()
.withSummary("Create multiple " + tableLabel + " records.")
.withTags(ListBuilder.of(tableLabel))
.withResponses(buildStandardErrorResponses())
)
);
*/
}
componentResponses.put(400, buildStandardErrorResponse("Bad Request. Some portion of the request's content was not acceptable to the server. See error message in body for details.", "Parameter id should be given an integer value, but received string: \"Foo\""));
componentResponses.put(401, buildStandardErrorResponse("Unauthorized. The required authentication credentials were missing or invalid.", "The required authentication credentials were missing or invalid."));
componentResponses.put(403, buildStandardErrorResponse("Forbidden. You do not have permission to access the requested resource.", "You do not have permission to access the requested resource."));
componentResponses.put(500, buildStandardErrorResponse("Internal Server Error. An error occurred in the server processing the request.", "Database connection error. Try again later."));
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecOutput();
output.setOpenAPI(openAPI);
output.setYaml(YamlUtils.toYaml(openAPI));
output.setJson(JsonUtils.toJson(openAPI));
return (output);
}
/*******************************************************************************
**
*******************************************************************************/
private Map<String, Example> buildOrderByExamples(String primaryKeyName, List<? extends QFieldMetaData> tableApiFields)
{
Map<String, Example> rs = new LinkedHashMap<>();
List<String> fieldsForExample4 = new ArrayList<>();
List<String> fieldsForExample5 = new ArrayList<>();
for(QFieldMetaData tableApiField : tableApiFields)
{
String name = tableApiField.getName();
if(primaryKeyName.equals(name) || fieldsForExample4.contains(name) || fieldsForExample5.contains(name))
{
continue;
}
if(!fieldsForExample4.contains(name) && fieldsForExample4.size() < 2)
{
fieldsForExample4.add(name);
}
else if(!fieldsForExample5.contains(name) && fieldsForExample5.size() < 3)
{
fieldsForExample5.add(name);
}
if(fieldsForExample5.size() == 3)
{
break;
}
}
rs.put(primaryKeyName, new ExampleWithSingleValue()
.withSummary("order by " + primaryKeyName + " (by default is ascending)")
.withValue("id"));
rs.put(primaryKeyName + "Desc", new ExampleWithSingleValue()
.withSummary("order by " + primaryKeyName + " (descending)")
.withValue("id desc"));
rs.put(primaryKeyName + "Asc", new ExampleWithSingleValue()
.withSummary("order by " + primaryKeyName + " (explicitly ascending)")
.withValue("id asc"));
if(fieldsForExample4.size() == 2)
{
String a = fieldsForExample4.get(0);
String b = fieldsForExample4.get(1);
String name = a + "And" + StringUtils.ucFirst(b);
rs.put(name, new ExampleWithSingleValue()
.withSummary("order by " + a + ", then by " + b + " (both ascending)")
.withValue(a + ", " + b));
}
if(fieldsForExample5.size() == 3)
{
String a = fieldsForExample5.get(0);
String b = fieldsForExample5.get(1);
String c = fieldsForExample5.get(2);
String name = a + "And" + StringUtils.ucFirst(b) + "And" + StringUtils.ucFirst(c);
rs.put(name, new ExampleWithSingleValue()
.withSummary("order by " + a + " descending, then by " + b + " ascending, then by " + c)
.withValue(a + " desc, " + b + " asc, " + c));
}
return (rs);
}
/*******************************************************************************
**
*******************************************************************************/
private String getFieldType(QFieldMetaData field)
{
return (getFieldType(field.getType()));
}
/*******************************************************************************
**
*******************************************************************************/
@SuppressWarnings("checkstyle:indentation")
private String getFieldType(QFieldType type)
{
return switch(type)
{
case STRING -> "string";
case INTEGER -> "integer";
case DECIMAL -> null;
case BOOLEAN -> null;
case DATE -> null;
case TIME -> null;
case DATE_TIME -> null;
case TEXT -> null;
case HTML -> null;
case PASSWORD -> null;
case BLOB -> null;
};
}
/*******************************************************************************
**
*******************************************************************************/
private static Map<Integer, Response> buildStandardErrorResponses()
{
return MapBuilder.of(
400, new Response().withRef("#/components/responses/400"),
401, new Response().withRef("#/components/responses/401"),
403, new Response().withRef("#/components/responses/403"),
500, new Response().withRef("#/components/responses/500")
);
}
/*******************************************************************************
**
*******************************************************************************/
private static Response buildStandardErrorResponse(String description)
{
return buildStandardErrorResponse(description, description);
}
/*******************************************************************************
**
*******************************************************************************/
private static Response buildStandardErrorResponse(String description, String example)
{
return new Response()
.withDescription(description)
.withContent(MapBuilder.of("application/json", new Content()
.withSchema(new Schema()
.withType("object")
.withProperties(MapBuilder.of("error", new Schema()
.withType("string")
.withExample(example)
))
)
));
}
// /*******************************************************************************
// **
// *******************************************************************************/
// @Override
// public GenerateSwaggerOutput execute(GenerateSwaggerInput input) throws QException
// {
// QInstance qInstance = QContext.getQInstance();
//
// LinkedHashMap<String, Serializable> swagger = new LinkedHashMap<>();
// swagger.put("openapi", "3.0.3");
//
// LinkedHashMap<String, Serializable> info = new LinkedHashMap<>();
// swagger.put("info", info);
//
// // todo - add a whole section of this to meta data?
// info.put("title", "QQQ API");
// info.put("description", """
// This is your api description!
// """);
// info.put("termsOfService", "http://swagger.io/terms/");
// info.put("contact", new LinkedHashMap<>(MapBuilder.of("email", "apiteam@swagger.io")));
// info.put("license", new LinkedHashMap<>(MapBuilder.of(
// "name", "Apache 2.0",
// "url", "http://www.apache.org/licenses/LICENSE-2.0.html"
// )));
// info.put("version", "1.0.11");
//
// swagger.put("externalDocs", new LinkedHashMap<>(MapBuilder.of(
// "description", "Find out more at:",
// "url", "http://swagger.io"
// )));
// swagger.put("servers", new LinkedHashMap<>(MapBuilder.of(
// "url", new ArrayList<>(ListBuilder.of("https://petstore3.swagger.io/api/v3"))
// )));
//
// ArrayList<LinkedHashMap<String, Serializable>> tags = new ArrayList<>();
// swagger.put("tags", tags);
// for(QTableMetaData table : qInstance.getTables().values())
// {
// tags.add(new LinkedHashMap<>(MapBuilder.of(
// "name", table.getName(),
// "description", "Operations on the " + table.getLabel() + " table."
// )));
// }
//
// LinkedHashMap<String, Serializable> paths = new LinkedHashMap<>();
// swagger.put("paths", paths);
// for(QTableMetaData table : qInstance.getTables().values())
// {
// String primaryKeyLabel = table.getField(table.getPrimaryKeyField()).getLabel();
// String primaryKeyName = table.getPrimaryKeyField();
//
// LinkedHashMap<String, Serializable> path = new LinkedHashMap<>();
// paths.put("/" + table.getName() + "/{" + primaryKeyName + "}", path);
//
// LinkedHashMap<String, Serializable> get = new LinkedHashMap<>(MapBuilder.of(
// "tags", new ArrayList<>(ListBuilder.of(table.getName())),
// "summary", "Find " + table.getLabel() + " by " + primaryKeyLabel + ".",
// "description", "Returns a single " + table.getLabel(),
// "operationId", "get" + StringUtils.ucFirst(table.getName()) + "By" + StringUtils.ucFirst(primaryKeyName),
// "parameters", new ArrayList<>(ListBuilder.of(
// new LinkedHashMap<>(MapBuilder.of(
// "name", primaryKeyName,
// "in", "path",
// "description", primaryKeyLabel + " of " + table.getLabel() + " to return",
// "required", true,
// "schema", new LinkedHashMap<>(MapBuilder.of(
// "type", "integer", // todo - get from field/type.
// "format", "int32"
// )
// ))
// ))),
// "responses", new LinkedHashMap<>(MapBuilder.of(
// "200", new LinkedHashMap<>(MapBuilder.of(
// "description", "Successfully got " + table.getLabel()
// )),
// "401", new LinkedHashMap<>(MapBuilder.of(
// "description", "Unauthorized. Security credentials were eitehr missing or invalid."
// )),
// "403", new LinkedHashMap<>(MapBuilder.of(
// "description", "Forbidden. The credentials provided do not have permission to access the requested resource."
// ))
// ))
// ));
//
// path.put("get", get);
// }
//
// System.out.println(YamlUtils.toYaml(swagger));
//
// return null;
// }
}

View File

@ -0,0 +1,152 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.actions;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.api.ApiMiddlewareType;
import com.kingsrook.qqq.api.model.APIVersion;
import com.kingsrook.qqq.api.model.APIVersionRange;
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsOutput;
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.fields.RemovedApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
import com.kingsrook.qqq.backend.core.actions.AbstractQActionFunction;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
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.StringUtils;
/*******************************************************************************
** For a given table (name) and API version, return the list of fields that apply
** for the API.
*******************************************************************************/
public class GetTableApiFieldsAction extends AbstractQActionFunction<GetTableApiFieldsInput, GetTableApiFieldsOutput>
{
/*******************************************************************************
**
*******************************************************************************/
public GetTableApiFieldsOutput execute(GetTableApiFieldsInput input) throws QException
{
List<QFieldMetaData> fields = new ArrayList<>();
QTableMetaData table = QContext.getQInstance().getTable(input.getTableName());
if(table == null)
{
throw (new QException("Unrecognized table name: " + input.getTableName()));
}
// todo - verify the table is in this version?
APIVersion version = new APIVersion(input.getVersion());
// todo - validate the version?
///////////////////////////////////////////////////////
// get fields on the table which are in this version //
///////////////////////////////////////////////////////
for(QFieldMetaData field : table.getFields().values())
{
if(getApiVersionRange(field).includes(version))
{
fields.add(field);
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////
// look for removed fields (e.g., not currently in the table anymore), that are in this version //
//////////////////////////////////////////////////////////////////////////////////////////////////
for(RemovedApiFieldMetaData removedApiField : CollectionUtils.nonNullList(getRemovedApiFields(table)))
{
APIVersionRange versionRange = getApiVersionRangeForRemovedField(removedApiField);
if(versionRange.includes(version))
{
// todo - dress this up w/ the old stuff
fields.add(removedApiField);
}
}
return (new GetTableApiFieldsOutput().withFields(fields));
}
/*******************************************************************************
**
*******************************************************************************/
private APIVersionRange getApiVersionRangeForRemovedField(RemovedApiFieldMetaData field)
{
ApiFieldMetaData middlewareMetaData = ApiMiddlewareType.getApiFieldMetaData(field);
if(middlewareMetaData != null && middlewareMetaData.getInitialVersion() != null)
{
if(StringUtils.hasContent(field.getFinalVersion()))
{
return (APIVersionRange.betweenAndIncluding(middlewareMetaData.getInitialVersion(), field.getFinalVersion()));
}
else
{
throw (new IllegalStateException("RemovedApiFieldMetaData for field [" + field.getName() + "] did not specify a finalVersion."));
}
}
else
{
throw (new IllegalStateException("RemovedApiFieldMetaData for field [" + field.getName() + "] did not specify an initialVersion."));
}
}
/*******************************************************************************
**
*******************************************************************************/
private APIVersionRange getApiVersionRange(QFieldMetaData field)
{
ApiFieldMetaData middlewareMetaData = ApiMiddlewareType.getApiFieldMetaData(field);
if(middlewareMetaData != null && middlewareMetaData.getInitialVersion() != null)
{
return (APIVersionRange.afterAndIncluding(middlewareMetaData.getInitialVersion()));
}
return (APIVersionRange.none());
}
/*******************************************************************************
**
*******************************************************************************/
private List<RemovedApiFieldMetaData> getRemovedApiFields(QTableMetaData table)
{
ApiTableMetaData apiTableMetaData = ApiMiddlewareType.getApiTableMetaData(table);
if(apiTableMetaData != null)
{
return (apiTableMetaData.getRemovedApiFields());
}
return (null);
}
}

View File

@ -0,0 +1,366 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.javalin;
import java.io.Serializable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.kingsrook.qqq.api.ApiMiddlewareType;
import com.kingsrook.qqq.api.actions.GetTableApiFieldsAction;
import com.kingsrook.qqq.api.model.APIVersion;
import com.kingsrook.qqq.api.model.APIVersionRange;
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
import com.kingsrook.qqq.backend.core.actions.permissions.PermissionsHelper;
import com.kingsrook.qqq.backend.core.actions.permissions.TablePermissionSubType;
import com.kingsrook.qqq.backend.core.actions.tables.GetAction;
import com.kingsrook.qqq.backend.core.actions.tables.QueryAction;
import com.kingsrook.qqq.backend.core.exceptions.QAuthenticationException;
import com.kingsrook.qqq.backend.core.exceptions.QModuleDispatchException;
import com.kingsrook.qqq.backend.core.exceptions.QNotFoundException;
import com.kingsrook.qqq.backend.core.exceptions.QPermissionDeniedException;
import com.kingsrook.qqq.backend.core.exceptions.QUserFacingException;
import com.kingsrook.qqq.backend.core.logging.QLogger;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
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.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.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.ExceptionUtils;
import com.kingsrook.qqq.backend.core.utils.JsonUtils;
import com.kingsrook.qqq.backend.core.utils.StringUtils;
import com.kingsrook.qqq.backend.javalin.QJavalinAccessLogger;
import com.kingsrook.qqq.backend.javalin.QJavalinImplementation;
import com.kingsrook.qqq.backend.javalin.QJavalinUtils;
import io.javalin.apibuilder.ApiBuilder;
import io.javalin.apibuilder.EndpointGroup;
import io.javalin.http.Context;
import org.eclipse.jetty.http.HttpStatus;
import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair;
import static com.kingsrook.qqq.backend.javalin.QJavalinImplementation.SLOW_LOG_THRESHOLD_MS;
/*******************************************************************************
** methods for handling qqq API requests in javalin.
*******************************************************************************/
public class QJavalinApiHandler
{
private static final QLogger LOG = QLogger.getLogger(QJavalinApiHandler.class);
static QInstance qInstance;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public QJavalinApiHandler(QInstance qInstance)
{
QJavalinApiHandler.qInstance = qInstance;
}
/*******************************************************************************
** Define the routes
*******************************************************************************/
public static EndpointGroup getRoutes()
{
return (() ->
{
ApiBuilder.path("/api/{version}", () -> // todo - configurable, that /api/ bit?
{
ApiBuilder.path("/{tableName}", () ->
{
ApiBuilder.post("/", QJavalinApiHandler::doInsert);
ApiBuilder.get("/query", QJavalinApiHandler::doQuery);
ApiBuilder.post("/query", QJavalinApiHandler::doQuery);
ApiBuilder.get("/{primaryKey}", QJavalinApiHandler::doGet);
ApiBuilder.patch("/{primaryKey}", QJavalinApiHandler::doUpdate);
ApiBuilder.delete("/{primaryKey}", QJavalinApiHandler::doDelete);
// post("/bulk", QJavalinApiHandler::bulkInsert);
// patch("/bulk", QJavalinApiHandler::bulkUpdate);
// delete("/bulk", QJavalinApiHandler::bulkDelete);
});
});
});
}
/*******************************************************************************
**
*******************************************************************************/
public static void setupSession(Context context, AbstractActionInput input) throws QModuleDispatchException, QAuthenticationException
{
QJavalinImplementation.setupSession(context, input);
}
/*******************************************************************************
**
*******************************************************************************/
private static APIVersionRange getApiVersionRange(QTableMetaData table)
{
ApiTableMetaData middlewareMetaData = ApiMiddlewareType.getApiTableMetaData(table);
if(middlewareMetaData != null && middlewareMetaData.getInitialVersion() != null)
{
return (APIVersionRange.afterAndIncluding(middlewareMetaData.getInitialVersion()));
}
return (APIVersionRange.none());
}
/*******************************************************************************
**
*******************************************************************************/
private static void doGet(Context context)
{
String version = context.pathParam("version");
String tableName = context.pathParam("table");
String primaryKey = context.pathParam("primaryKey");
try
{
// todo - make sure version is known in this instance
// todo - make sure table is supported in this version
QTableMetaData table = qInstance.getTable(tableName);
if(table == null)
{
throw (new QNotFoundException("Could not find any resources at path " + context.path()));
}
if(!getApiVersionRange(table).includes(new APIVersion(version)))
{
throw (new QNotFoundException("This version of this API does not contain the resource path " + context.path()));
}
GetInput getInput = new GetInput();
setupSession(context, getInput);
QJavalinAccessLogger.logStart("get", logPair("table", tableName), logPair("primaryKey", primaryKey));
getInput.setTableName(tableName);
// i think not for api... getInput.setShouldGenerateDisplayValues(true);
getInput.setShouldTranslatePossibleValues(true);
PermissionsHelper.checkTablePermissionThrowing(getInput, TablePermissionSubType.READ);
// todo - validate that the primary key is of the proper type (e.g,. not a string for an id field)
// and throw a 400-series error (tell the user bad-request), rather than, we're doing a 500 (server error)
getInput.setPrimaryKey(primaryKey);
GetAction getAction = new GetAction();
GetOutput getOutput = getAction.execute(getInput);
///////////////////////////////////////////////////////
// throw a not found error if the record isn't found //
///////////////////////////////////////////////////////
QRecord record = getOutput.getRecord();
if(record == null)
{
throw (new QNotFoundException("Could not find " + table.getLabel() + " with "
+ table.getFields().get(table.getPrimaryKeyField()).getLabel() + " of " + primaryKey));
}
List<? extends QFieldMetaData> tableApiFields = new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
Map<String, Serializable> outputRecord = new LinkedHashMap<>();
for(QFieldMetaData tableApiField : tableApiFields)
{
// todo - what about display values / possible values
// todo - handle removed-from-this-version fields!!
outputRecord.put(tableApiField.getName(), record.getValue(tableApiField.getName()));
}
QJavalinAccessLogger.logEndSuccess();
context.result(JsonUtils.toJson(outputRecord));
}
catch(Exception e)
{
QJavalinAccessLogger.logEndFail(e);
QJavalinImplementation.handleException(context, e);
}
}
/*******************************************************************************
**
*******************************************************************************/
private static void doQuery(Context context)
{
String table = context.pathParam("table");
String filter = null;
try
{
QueryInput queryInput = new QueryInput();
setupSession(context, queryInput);
QJavalinAccessLogger.logStart("query", logPair("table", table));
queryInput.setTableName(table);
queryInput.setShouldGenerateDisplayValues(true);
queryInput.setShouldTranslatePossibleValues(true);
queryInput.setSkip(QJavalinUtils.integerQueryParam(context, "skip"));
queryInput.setLimit(QJavalinUtils.integerQueryParam(context, "limit"));
PermissionsHelper.checkTablePermissionThrowing(queryInput, TablePermissionSubType.READ);
filter = QJavalinUtils.stringQueryParam(context, "filter");
if(!StringUtils.hasContent(filter))
{
filter = context.formParam("filter");
}
if(filter != null)
{
queryInput.setFilter(JsonUtils.toObject(filter, QQueryFilter.class));
}
// queryInput.setQueryJoins(processQueryJoinsParam(context));
QueryAction queryAction = new QueryAction();
QueryOutput queryOutput = queryAction.execute(queryInput);
QJavalinAccessLogger.logEndSuccess(logPair("recordCount", queryOutput.getRecords().size()), QJavalinAccessLogger.logPairIfSlow("filter", filter, SLOW_LOG_THRESHOLD_MS));
context.result(JsonUtils.toJson(queryOutput));
}
catch(Exception e)
{
QJavalinAccessLogger.logEndFail(e, logPair("filter", filter));
handleException(context, e);
}
}
/*******************************************************************************
**
*******************************************************************************/
private static void doInsert(Context context)
{
}
/*******************************************************************************
**
*******************************************************************************/
private static void doUpdate(Context context)
{
}
/*******************************************************************************
**
*******************************************************************************/
private static void doDelete(Context context)
{
}
/*******************************************************************************
**
*******************************************************************************/
public static void handleException(Context context, Exception e)
{
handleException(null, context, e);
}
/*******************************************************************************
**
*******************************************************************************/
public static void handleException(HttpStatus.Code statusCode, Context context, Exception e)
{
QUserFacingException userFacingException = ExceptionUtils.findClassInRootChain(e, QUserFacingException.class);
if(userFacingException != null)
{
if(userFacingException instanceof QNotFoundException)
{
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.NOT_FOUND); // 404
respondWithError(context, statusCode, userFacingException.getMessage());
}
else
{
LOG.info("User-facing exception", e);
statusCode = Objects.requireNonNullElse(statusCode, HttpStatus.Code.INTERNAL_SERVER_ERROR); // 500
respondWithError(context, statusCode, userFacingException.getMessage());
}
}
else
{
if(e instanceof QAuthenticationException)
{
respondWithError(context, HttpStatus.Code.UNAUTHORIZED, e.getMessage()); // 401
return;
}
if(e instanceof QPermissionDeniedException)
{
respondWithError(context, HttpStatus.Code.FORBIDDEN, e.getMessage()); // 403
return;
}
////////////////////////////////
// default exception handling //
////////////////////////////////
LOG.warn("Exception in javalin request", e);
respondWithError(context, HttpStatus.Code.INTERNAL_SERVER_ERROR, e.getClass().getSimpleName() + " (" + e.getMessage() + ")"); // 500
}
}
/*******************************************************************************
**
*******************************************************************************/
public static void respondWithError(Context context, HttpStatus.Code statusCode, String errorMessage)
{
context.status(statusCode.getCode());
context.result(JsonUtils.toJson(Map.of("error", errorMessage)));
}
}

View File

@ -0,0 +1,107 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model;
import java.util.Objects;
/*******************************************************************************
** Should work as well for https://semver.org/spec/v2.0.0.html or https://calver.org/
** or simple increasing integers, or ?
*******************************************************************************/
public class APIVersion implements Comparable<APIVersion>
{
private String version;
private String[] parts;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public APIVersion(String version)
{
this.version = version;
this.parts = version.split("[.-]");
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public int compareTo(APIVersion that)
{
int i = 0;
while(true)
{
if(i >= this.parts.length && i >= that.parts.length)
{
return (0);
}
else if(i >= this.parts.length)
{
return (1); // todo - review
}
else if(i >= that.parts.length)
{
return (0); // todo - review
}
else
{
String thisPart = this.parts[i];
String thatPart = that.parts[i];
if(!Objects.equals(thisPart, thatPart))
{
try
{
Integer thisInt = Integer.parseInt(thisPart);
Integer thatInt = Integer.parseInt(thatPart);
return (thisInt.compareTo(thatInt));
}
catch(Exception e)
{
//////////////////////////////////////////////////////////////////////////
// if either doesn't parse as an integer, then compare them as strings. //
//////////////////////////////////////////////////////////////////////////
return (thisPart.compareTo(thatPart));
}
}
}
i++;
}
}
/*******************************************************************************
**
*******************************************************************************/
@Override
public String toString()
{
return (version);
}
}

View File

@ -0,0 +1,364 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model;
/*******************************************************************************
**
*******************************************************************************/
public class APIVersionRange
{
private APIVersion start;
private Boolean startInclusive = true;
private APIVersion end;
private Boolean endInclusive = true;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public APIVersionRange()
{
}
/*******************************************************************************
**
*******************************************************************************/
private APIVersionRange(APIVersion start, Boolean startInclusive, APIVersion end, Boolean endInclusive)
{
this.start = start;
this.startInclusive = startInclusive;
this.end = end;
this.endInclusive = endInclusive;
}
/*******************************************************************************
** return a version range that includes no versions.
*******************************************************************************/
public static APIVersionRange none()
{
return (new APIVersionRange()
{
@Override
public boolean includes(APIVersion apiVersion)
{
return (false);
}
});
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange afterAndIncluding(APIVersion start)
{
return (new APIVersionRange(start, true, null, null));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange afterAndIncluding(String start)
{
return (afterAndIncluding(new APIVersion(start)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange afterButExcluding(String start)
{
return (afterButExcluding(new APIVersion(start)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange afterButExcluding(APIVersion start)
{
return (new APIVersionRange(start, false, null, null));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange beforeAndIncluding(APIVersion end)
{
return (new APIVersionRange(null, null, end, true));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange beforeAndIncluding(String end)
{
return (beforeAndIncluding(new APIVersion(end)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange beforeButExcluding(String end)
{
return (beforeButExcluding(new APIVersion(end)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange beforeButExcluding(APIVersion end)
{
return (new APIVersionRange(null, null, end, false));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange betweenAndIncluding(APIVersion start, APIVersion end)
{
return (new APIVersionRange(start, true, end, true));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange betweenAndIncluding(String start, String end)
{
return (betweenAndIncluding(new APIVersion(start), new APIVersion(end)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange betweenButExcluding(String start, String end)
{
return (betweenButExcluding(new APIVersion(start), new APIVersion(end)));
}
/*******************************************************************************
**
*******************************************************************************/
public static APIVersionRange betweenButExcluding(APIVersion start, APIVersion end)
{
return (new APIVersionRange(start, false, end, false));
}
/*******************************************************************************
** Getter for start
*******************************************************************************/
public APIVersion getStart()
{
return (this.start);
}
/*******************************************************************************
** Setter for start
*******************************************************************************/
public void setStart(APIVersion start)
{
this.start = start;
}
/*******************************************************************************
** Fluent setter for start
*******************************************************************************/
public APIVersionRange withStart(APIVersion start)
{
this.start = start;
return (this);
}
/*******************************************************************************
** Getter for startInclusive
*******************************************************************************/
public Boolean getStartInclusive()
{
return (this.startInclusive);
}
/*******************************************************************************
** Setter for startInclusive
*******************************************************************************/
public void setStartInclusive(Boolean startInclusive)
{
this.startInclusive = startInclusive;
}
/*******************************************************************************
** Fluent setter for startInclusive
*******************************************************************************/
public APIVersionRange withStartInclusive(Boolean startInclusive)
{
this.startInclusive = startInclusive;
return (this);
}
/*******************************************************************************
** Getter for end
*******************************************************************************/
public APIVersion getEnd()
{
return (this.end);
}
/*******************************************************************************
** Setter for end
*******************************************************************************/
public void setEnd(APIVersion end)
{
this.end = end;
}
/*******************************************************************************
** Fluent setter for end
*******************************************************************************/
public APIVersionRange withEnd(APIVersion end)
{
this.end = end;
return (this);
}
/*******************************************************************************
** Getter for endInclusive
*******************************************************************************/
public Boolean getEndInclusive()
{
return (this.endInclusive);
}
/*******************************************************************************
** Setter for endInclusive
*******************************************************************************/
public void setEndInclusive(Boolean endInclusive)
{
this.endInclusive = endInclusive;
}
/*******************************************************************************
** Fluent setter for endInclusive
*******************************************************************************/
public APIVersionRange withEndInclusive(Boolean endInclusive)
{
this.endInclusive = endInclusive;
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public boolean includes(APIVersion apiVersion)
{
if(start != null)
{
if(startInclusive)
{
if(apiVersion.compareTo(start) < 0)
{
return (false);
}
}
else
{
if(apiVersion.compareTo(start) <= 0)
{
return (false);
}
}
}
if(end != null)
{
if(endInclusive)
{
if(apiVersion.compareTo(end) > 0)
{
return (false);
}
}
else
{
if(apiVersion.compareTo(end) >= 0)
{
return (false);
}
}
}
return (true);
}
}

View File

@ -0,0 +1,66 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.actions;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
/*******************************************************************************
**
*******************************************************************************/
public class GenerateOpenApiSpecInput extends AbstractActionInput
{
private String version;
/*******************************************************************************
** Getter for version
*******************************************************************************/
public String getVersion()
{
return (this.version);
}
/*******************************************************************************
** Setter for version
*******************************************************************************/
public void setVersion(String version)
{
this.version = version;
}
/*******************************************************************************
** Fluent setter for version
*******************************************************************************/
public GenerateOpenApiSpecInput withVersion(String version)
{
this.version = version;
return (this);
}
}

View File

@ -0,0 +1,131 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.actions;
import com.kingsrook.qqq.api.model.openapi.OpenAPI;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
/*******************************************************************************
**
*******************************************************************************/
public class GenerateOpenApiSpecOutput extends AbstractActionOutput
{
private OpenAPI openAPI;
private String yaml;
private String json;
/*******************************************************************************
** Getter for openAPI
*******************************************************************************/
public OpenAPI getOpenAPI()
{
return (this.openAPI);
}
/*******************************************************************************
** Setter for openAPI
*******************************************************************************/
public void setOpenAPI(OpenAPI openAPI)
{
this.openAPI = openAPI;
}
/*******************************************************************************
** Fluent setter for openAPI
*******************************************************************************/
public GenerateOpenApiSpecOutput withOpenAPI(OpenAPI openAPI)
{
this.openAPI = openAPI;
return (this);
}
/*******************************************************************************
** Getter for yaml
*******************************************************************************/
public String getYaml()
{
return (this.yaml);
}
/*******************************************************************************
** Setter for yaml
*******************************************************************************/
public void setYaml(String yaml)
{
this.yaml = yaml;
}
/*******************************************************************************
** Fluent setter for yaml
*******************************************************************************/
public GenerateOpenApiSpecOutput withYaml(String yaml)
{
this.yaml = yaml;
return (this);
}
/*******************************************************************************
** Getter for json
*******************************************************************************/
public String getJson()
{
return (this.json);
}
/*******************************************************************************
** Setter for json
*******************************************************************************/
public void setJson(String json)
{
this.json = json;
}
/*******************************************************************************
** Fluent setter for json
*******************************************************************************/
public GenerateOpenApiSpecOutput withJson(String json)
{
this.json = json;
return (this);
}
}

View File

@ -0,0 +1,98 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.actions;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionInput;
/*******************************************************************************
**
*******************************************************************************/
public class GetTableApiFieldsInput extends AbstractActionInput
{
private String tableName;
private String version;
/*******************************************************************************
** Getter for version
*******************************************************************************/
public String getVersion()
{
return (this.version);
}
/*******************************************************************************
** Setter for version
*******************************************************************************/
public void setVersion(String version)
{
this.version = version;
}
/*******************************************************************************
** Fluent setter for version
*******************************************************************************/
public GetTableApiFieldsInput withVersion(String version)
{
this.version = version;
return (this);
}
/*******************************************************************************
** Getter for tableName
*******************************************************************************/
public String getTableName()
{
return (this.tableName);
}
/*******************************************************************************
** Setter for tableName
*******************************************************************************/
public void setTableName(String tableName)
{
this.tableName = tableName;
}
/*******************************************************************************
** Fluent setter for tableName
*******************************************************************************/
public GetTableApiFieldsInput withTableName(String tableName)
{
this.tableName = tableName;
return (this);
}
}

View File

@ -0,0 +1,68 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.actions;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.actions.AbstractActionOutput;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
/*******************************************************************************
**
*******************************************************************************/
public class GetTableApiFieldsOutput extends AbstractActionOutput
{
private List<? extends QFieldMetaData> fields;
/*******************************************************************************
** Getter for fields
*******************************************************************************/
public List<? extends QFieldMetaData> getFields()
{
return (this.fields);
}
/*******************************************************************************
** Setter for fields
*******************************************************************************/
public void setFields(List<? extends QFieldMetaData> fields)
{
this.fields = fields;
}
/*******************************************************************************
** Fluent setter for fields
*******************************************************************************/
public GetTableApiFieldsOutput withFields(List<? extends QFieldMetaData> fields)
{
this.fields = fields;
return (this);
}
}

View File

@ -0,0 +1,178 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.metadata;
import java.util.List;
import com.kingsrook.qqq.api.model.APIVersion;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.QMiddlewareInstanceMetaData;
/*******************************************************************************
**
*******************************************************************************/
public class ApiInstanceMetaData extends QMiddlewareInstanceMetaData
{
private APIVersion currentVersion;
private List<APIVersion> supportedVersions;
private List<APIVersion> pastVersions;
private List<APIVersion> futureVersions;
/*******************************************************************************
**
*******************************************************************************/
@Override
public void validate(QInstance qInstance)
{
// todo - version is set
// todo - past versions all < current < all future
// todo - any version specified anywhere is one of the known
}
/*******************************************************************************
** Getter for currentVersion
*******************************************************************************/
public APIVersion getCurrentVersion()
{
return (this.currentVersion);
}
/*******************************************************************************
** Setter for currentVersion
*******************************************************************************/
public void setCurrentVersion(APIVersion currentVersion)
{
this.currentVersion = currentVersion;
}
/*******************************************************************************
** Fluent setter for currentVersion
*******************************************************************************/
public ApiInstanceMetaData withCurrentVersion(APIVersion currentVersion)
{
this.currentVersion = currentVersion;
return (this);
}
/*******************************************************************************
** Getter for pastVersions
*******************************************************************************/
public List<APIVersion> getPastVersions()
{
return (this.pastVersions);
}
/*******************************************************************************
** Setter for pastVersions
*******************************************************************************/
public void setPastVersions(List<APIVersion> pastVersions)
{
this.pastVersions = pastVersions;
}
/*******************************************************************************
** Fluent setter for pastVersions
*******************************************************************************/
public ApiInstanceMetaData withPastVersions(List<APIVersion> pastVersions)
{
this.pastVersions = pastVersions;
return (this);
}
/*******************************************************************************
** Getter for futureVersions
*******************************************************************************/
public List<APIVersion> getFutureVersions()
{
return (this.futureVersions);
}
/*******************************************************************************
** Setter for futureVersions
*******************************************************************************/
public void setFutureVersions(List<APIVersion> futureVersions)
{
this.futureVersions = futureVersions;
}
/*******************************************************************************
** Fluent setter for futureVersions
*******************************************************************************/
public ApiInstanceMetaData withFutureVersions(List<APIVersion> futureVersions)
{
this.futureVersions = futureVersions;
return (this);
}
/*******************************************************************************
** Getter for supportedVersions
*******************************************************************************/
public List<APIVersion> getSupportedVersions()
{
return (this.supportedVersions);
}
/*******************************************************************************
** Setter for supportedVersions
*******************************************************************************/
public void setSupportedVersions(List<APIVersion> supportedVersions)
{
this.supportedVersions = supportedVersions;
}
/*******************************************************************************
** Fluent setter for supportedVersions
*******************************************************************************/
public ApiInstanceMetaData withSupportedVersions(List<APIVersion> supportedVersions)
{
this.supportedVersions = supportedVersions;
return (this);
}
}

View File

@ -0,0 +1,30 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.metadata;
/*******************************************************************************
**
*******************************************************************************/
public class QAPIMetaData
{
}

View File

@ -0,0 +1,77 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.metadata.fields;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QMiddlewareFieldMetaData;
/*******************************************************************************
**
*******************************************************************************/
public class ApiFieldMetaData extends QMiddlewareFieldMetaData
{
private String initialVersion;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public ApiFieldMetaData()
{
setType("api");
}
/*******************************************************************************
** Getter for initialVersion
*******************************************************************************/
public String getInitialVersion()
{
return (this.initialVersion);
}
/*******************************************************************************
** Setter for initialVersion
*******************************************************************************/
public void setInitialVersion(String initialVersion)
{
this.initialVersion = initialVersion;
}
/*******************************************************************************
** Fluent setter for initialVersion
*******************************************************************************/
public ApiFieldMetaData withInitialVersion(String initialVersion)
{
this.initialVersion = initialVersion;
return (this);
}
}

View File

@ -0,0 +1,121 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.metadata.fields;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType;
/*******************************************************************************
**
*******************************************************************************/
public class RemovedApiFieldMetaData extends QFieldMetaData
{
private String finalVersion;
private String replacedByFieldName;
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public RemovedApiFieldMetaData()
{
super();
}
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public RemovedApiFieldMetaData(String name, QFieldType type)
{
super(name, type);
}
/*******************************************************************************
** Getter for replacedByFieldName
*******************************************************************************/
public String getReplacedByFieldName()
{
return (this.replacedByFieldName);
}
/*******************************************************************************
** Setter for replacedByFieldName
*******************************************************************************/
public void setReplacedByFieldName(String replacedByFieldName)
{
this.replacedByFieldName = replacedByFieldName;
}
/*******************************************************************************
** Fluent setter for replacedByFieldName
*******************************************************************************/
public RemovedApiFieldMetaData withReplacedByFieldName(String replacedByFieldName)
{
this.replacedByFieldName = replacedByFieldName;
return (this);
}
/*******************************************************************************
** Getter for finalVersion
*******************************************************************************/
public String getFinalVersion()
{
return (this.finalVersion);
}
/*******************************************************************************
** Setter for finalVersion
*******************************************************************************/
public void setFinalVersion(String finalVersion)
{
this.finalVersion = finalVersion;
}
/*******************************************************************************
** Fluent setter for finalVersion
*******************************************************************************/
public RemovedApiFieldMetaData withFinalVersion(String finalVersion)
{
this.finalVersion = finalVersion;
return (this);
}
}

View File

@ -0,0 +1,192 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.metadata.tables;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.api.ApiMiddlewareType;
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.fields.RemovedApiFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QMiddlewareTableMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
/*******************************************************************************
**
*******************************************************************************/
public class ApiTableMetaData extends QMiddlewareTableMetaData
{
private String initialVersion;
private String finalVersion;
private List<RemovedApiFieldMetaData> removedApiFields;
/*******************************************************************************
**
*******************************************************************************/
@Override
public void enrich(QTableMetaData table)
{
super.enrich(table);
if(initialVersion != null)
{
for(QFieldMetaData field : table.getFields().values())
{
if(field.getMiddlewareMetaData(ApiMiddlewareType.NAME) == null)
{
field.withMiddlewareMetaData(new ApiFieldMetaData());
}
ApiFieldMetaData apiFieldMetaData = (ApiFieldMetaData) field.getMiddlewareMetaData(ApiMiddlewareType.NAME);
if(apiFieldMetaData.getInitialVersion() == null)
{
apiFieldMetaData.setInitialVersion(initialVersion);
}
}
}
}
/*******************************************************************************
** Constructor
**
*******************************************************************************/
public ApiTableMetaData()
{
setType("api");
}
/*******************************************************************************
** Getter for removedApiFields
*******************************************************************************/
public List<RemovedApiFieldMetaData> getRemovedApiFields()
{
return (this.removedApiFields);
}
/*******************************************************************************
** Setter for removedApiFields
*******************************************************************************/
public void setRemovedApiFields(List<RemovedApiFieldMetaData> removedApiFields)
{
this.removedApiFields = removedApiFields;
}
/*******************************************************************************
** Fluent setter for removedApiFields
*******************************************************************************/
public ApiTableMetaData withRemovedApiFields(List<RemovedApiFieldMetaData> removedApiFields)
{
this.removedApiFields = removedApiFields;
return (this);
}
/*******************************************************************************
** Fluent setter for a single removedApiField
*******************************************************************************/
public ApiTableMetaData withRemovedApiField(RemovedApiFieldMetaData removedApiField)
{
if(this.removedApiFields == null)
{
this.removedApiFields = new ArrayList<>();
}
this.removedApiFields.add(removedApiField);
return (this);
}
/*******************************************************************************
** Getter for initialVersion
*******************************************************************************/
public String getInitialVersion()
{
return (this.initialVersion);
}
/*******************************************************************************
** Setter for initialVersion
*******************************************************************************/
public void setInitialVersion(String initialVersion)
{
this.initialVersion = initialVersion;
}
/*******************************************************************************
** Fluent setter for initialVersion
*******************************************************************************/
public ApiTableMetaData withInitialVersion(String initialVersion)
{
this.initialVersion = initialVersion;
return (this);
}
/*******************************************************************************
** Getter for finalVersion
*******************************************************************************/
public String getFinalVersion()
{
return (this.finalVersion);
}
/*******************************************************************************
** Setter for finalVersion
*******************************************************************************/
public void setFinalVersion(String finalVersion)
{
this.finalVersion = finalVersion;
}
/*******************************************************************************
** Fluent setter for finalVersion
*******************************************************************************/
public ApiTableMetaData withFinalVersion(String finalVersion)
{
this.finalVersion = finalVersion;
return (this);
}
}

View File

@ -0,0 +1,130 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.Map;
/*******************************************************************************
**
*******************************************************************************/
public class Components
{
private Map<String, Example> examples;
private Map<String, Schema> schemas;
private Map<Integer, Response> responses;
/*******************************************************************************
** Getter for examples
*******************************************************************************/
public Map<String, Example> getExamples()
{
return (this.examples);
}
/*******************************************************************************
** Setter for examples
*******************************************************************************/
public void setExamples(Map<String, Example> examples)
{
this.examples = examples;
}
/*******************************************************************************
** Fluent setter for examples
*******************************************************************************/
public Components withExamples(Map<String, Example> examples)
{
this.examples = examples;
return (this);
}
/*******************************************************************************
** Getter for schemas
*******************************************************************************/
public Map<String, Schema> getSchemas()
{
return (this.schemas);
}
/*******************************************************************************
** Setter for schemas
*******************************************************************************/
public void setSchemas(Map<String, Schema> schemas)
{
this.schemas = schemas;
}
/*******************************************************************************
** Fluent setter for schemas
*******************************************************************************/
public Components withSchemas(Map<String, Schema> schemas)
{
this.schemas = schemas;
return (this);
}
/*******************************************************************************
** Getter for responses
*******************************************************************************/
public Map<Integer, Response> getResponses()
{
return (this.responses);
}
/*******************************************************************************
** Setter for responses
*******************************************************************************/
public void setResponses(Map<Integer, Response> responses)
{
this.responses = responses;
}
/*******************************************************************************
** Fluent setter for responses
*******************************************************************************/
public Components withResponses(Map<Integer, Response> responses)
{
this.responses = responses;
return (this);
}
}

View File

@ -0,0 +1,63 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Contact
{
private String email;
/*******************************************************************************
** Getter for email
*******************************************************************************/
public String getEmail()
{
return (this.email);
}
/*******************************************************************************
** Setter for email
*******************************************************************************/
public void setEmail(String email)
{
this.email = email;
}
/*******************************************************************************
** Fluent setter for email
*******************************************************************************/
public Contact withEmail(String email)
{
this.email = email;
return (this);
}
}

View File

@ -0,0 +1,63 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Content
{
private Schema schema;
/*******************************************************************************
** Getter for schema
*******************************************************************************/
public Schema getSchema()
{
return (this.schema);
}
/*******************************************************************************
** Setter for schema
*******************************************************************************/
public void setSchema(Schema schema)
{
this.schema = schema;
}
/*******************************************************************************
** Fluent setter for schema
*******************************************************************************/
public Content withSchema(Schema schema)
{
this.schema = schema;
return (this);
}
}

View File

@ -0,0 +1,63 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public abstract class Example
{
private String summary;
/*******************************************************************************
** Getter for summary
*******************************************************************************/
public String getSummary()
{
return (this.summary);
}
/*******************************************************************************
** Setter for summary
*******************************************************************************/
public void setSummary(String summary)
{
this.summary = summary;
}
/*******************************************************************************
** Fluent setter for summary
*******************************************************************************/
public Example withSummary(String summary)
{
this.summary = summary;
return (this);
}
}

View File

@ -0,0 +1,78 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.List;
/*******************************************************************************
**
*******************************************************************************/
public class ExampleWithListValue extends Example
{
private List<String> value;
/*******************************************************************************
**
*******************************************************************************/
@Override
public ExampleWithListValue withSummary(String summary)
{
super.withSummary(summary);
return (this);
}
/*******************************************************************************
** Getter for value
*******************************************************************************/
public List<String> getValue()
{
return (this.value);
}
/*******************************************************************************
** Setter for value
*******************************************************************************/
public void setValue(List<String> value)
{
this.value = value;
}
/*******************************************************************************
** Fluent setter for value
*******************************************************************************/
public ExampleWithListValue withValue(List<String> value)
{
this.value = value;
return (this);
}
}

View File

@ -0,0 +1,75 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class ExampleWithSingleValue extends Example
{
private String value;
/*******************************************************************************
**
*******************************************************************************/
@Override
public ExampleWithSingleValue withSummary(String summary)
{
super.withSummary(summary);
return (this);
}
/*******************************************************************************
** Getter for value
*******************************************************************************/
public String getValue()
{
return (this.value);
}
/*******************************************************************************
** Setter for value
*******************************************************************************/
public void setValue(String value)
{
this.value = value;
}
/*******************************************************************************
** Fluent setter for value
*******************************************************************************/
public ExampleWithSingleValue withValue(String value)
{
this.value = value;
return (this);
}
}

View File

@ -0,0 +1,95 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class ExternalDocs
{
private String description;
private String url;
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public ExternalDocs withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for url
*******************************************************************************/
public String getUrl()
{
return (this.url);
}
/*******************************************************************************
** Setter for url
*******************************************************************************/
public void setUrl(String url)
{
this.url = url;
}
/*******************************************************************************
** Fluent setter for url
*******************************************************************************/
public ExternalDocs withUrl(String url)
{
this.url = url;
return (this);
}
}

View File

@ -0,0 +1,191 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Info
{
private String title;
private String description;
private String termsOfService;
private Contact contact;
private String version;
/*******************************************************************************
** Getter for title
*******************************************************************************/
public String getTitle()
{
return (this.title);
}
/*******************************************************************************
** Setter for title
*******************************************************************************/
public void setTitle(String title)
{
this.title = title;
}
/*******************************************************************************
** Fluent setter for title
*******************************************************************************/
public Info withTitle(String title)
{
this.title = title;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Info withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for termsOfService
*******************************************************************************/
public String getTermsOfService()
{
return (this.termsOfService);
}
/*******************************************************************************
** Setter for termsOfService
*******************************************************************************/
public void setTermsOfService(String termsOfService)
{
this.termsOfService = termsOfService;
}
/*******************************************************************************
** Fluent setter for termsOfService
*******************************************************************************/
public Info withTermsOfService(String termsOfService)
{
this.termsOfService = termsOfService;
return (this);
}
/*******************************************************************************
** Getter for contact
*******************************************************************************/
public Contact getContact()
{
return (this.contact);
}
/*******************************************************************************
** Setter for contact
*******************************************************************************/
public void setContact(Contact contact)
{
this.contact = contact;
}
/*******************************************************************************
** Fluent setter for contact
*******************************************************************************/
public Info withContact(Contact contact)
{
this.contact = contact;
return (this);
}
/*******************************************************************************
** Getter for version
*******************************************************************************/
public String getVersion()
{
return (this.version);
}
/*******************************************************************************
** Setter for version
*******************************************************************************/
public void setVersion(String version)
{
this.version = version;
}
/*******************************************************************************
** Fluent setter for version
*******************************************************************************/
public Info withVersion(String version)
{
this.version = version;
return (this);
}
}

View File

@ -0,0 +1,306 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/*******************************************************************************
**
*******************************************************************************/
public class Method
{
private String method;
private String summary;
private String description;
private String operationId;
private List<String> tags;
private RequestBody requestBody;
private List<Parameter> parameters;
private Map<Integer, Response> responses;
/*******************************************************************************
** Getter for method
*******************************************************************************/
public String getMethod()
{
return (this.method);
}
/*******************************************************************************
** Setter for method
*******************************************************************************/
public void setMethod(String method)
{
this.method = method;
}
/*******************************************************************************
** Fluent setter for method
*******************************************************************************/
public Method withMethod(String method)
{
this.method = method;
return (this);
}
/*******************************************************************************
** Getter for summary
*******************************************************************************/
public String getSummary()
{
return (this.summary);
}
/*******************************************************************************
** Setter for summary
*******************************************************************************/
public void setSummary(String summary)
{
this.summary = summary;
}
/*******************************************************************************
** Fluent setter for summary
*******************************************************************************/
public Method withSummary(String summary)
{
this.summary = summary;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Method withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for operationId
*******************************************************************************/
public String getOperationId()
{
return (this.operationId);
}
/*******************************************************************************
** Setter for operationId
*******************************************************************************/
public void setOperationId(String operationId)
{
this.operationId = operationId;
}
/*******************************************************************************
** Fluent setter for operationId
*******************************************************************************/
public Method withOperationId(String operationId)
{
this.operationId = operationId;
return (this);
}
/*******************************************************************************
** Getter for tags
*******************************************************************************/
public List<String> getTags()
{
return (this.tags);
}
/*******************************************************************************
** Setter for tags
*******************************************************************************/
public void setTags(List<String> tags)
{
this.tags = tags;
}
/*******************************************************************************
** Fluent setter for tags
*******************************************************************************/
public Method withTags(List<String> tags)
{
this.tags = tags;
return (this);
}
/*******************************************************************************
** Getter for requestBody
*******************************************************************************/
public RequestBody getRequestBody()
{
return (this.requestBody);
}
/*******************************************************************************
** Setter for requestBody
*******************************************************************************/
public void setRequestBody(RequestBody requestBody)
{
this.requestBody = requestBody;
}
/*******************************************************************************
** Fluent setter for requestBody
*******************************************************************************/
public Method withRequestBody(RequestBody requestBody)
{
this.requestBody = requestBody;
return (this);
}
/*******************************************************************************
** Getter for parameters
*******************************************************************************/
public List<Parameter> getParameters()
{
return (this.parameters);
}
/*******************************************************************************
** Setter for parameters
*******************************************************************************/
public void setParameters(List<Parameter> parameters)
{
this.parameters = parameters;
}
/*******************************************************************************
** Fluent setter for parameters
*******************************************************************************/
public Method withParameters(List<Parameter> parameters)
{
this.parameters = parameters;
return (this);
}
/*******************************************************************************
** Getter for responses
*******************************************************************************/
public Map<Integer, Response> getResponses()
{
return (this.responses);
}
/*******************************************************************************
** Setter for responses
*******************************************************************************/
public void setResponses(Map<Integer, Response> responses)
{
this.responses = responses;
}
/*******************************************************************************
** Fluent setter for responses
*******************************************************************************/
public Method withResponses(Map<Integer, Response> responses)
{
this.responses = responses;
return (this);
}
/*******************************************************************************
**
*******************************************************************************/
public Method withResponse(Integer code, Response response)
{
if(this.responses == null)
{
this.responses = new LinkedHashMap<>();
}
this.responses.put(code, response);
return (this);
}
}

View File

@ -0,0 +1,271 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonIgnore;
/*******************************************************************************
**
*******************************************************************************/
public class OpenAPI
{
private String openapi = "3.0.3"; // todo not version
private Info info;
private ExternalDocs externalDocs;
private List<Server> servers;
private List<Tag> tags;
private Map<String, Path> paths;
private Components components;
/*******************************************************************************
** Getter for version
*******************************************************************************/
public String getOpenapi()
{
return (this.openapi);
}
/*******************************************************************************
** Getter for version
*******************************************************************************/
@JsonIgnore
public String getVersion()
{
return (this.openapi);
}
/*******************************************************************************
** Setter for version
*******************************************************************************/
public void setVersion(String version)
{
this.openapi = version;
}
/*******************************************************************************
** Fluent setter for version
*******************************************************************************/
public OpenAPI withVersion(String version)
{
this.openapi = version;
return (this);
}
/*******************************************************************************
** Getter for info
*******************************************************************************/
public Info getInfo()
{
return (this.info);
}
/*******************************************************************************
** Setter for info
*******************************************************************************/
public void setInfo(Info info)
{
this.info = info;
}
/*******************************************************************************
** Fluent setter for info
*******************************************************************************/
public OpenAPI withInfo(Info info)
{
this.info = info;
return (this);
}
/*******************************************************************************
** Getter for externalDocs
*******************************************************************************/
public ExternalDocs getExternalDocs()
{
return (this.externalDocs);
}
/*******************************************************************************
** Setter for externalDocs
*******************************************************************************/
public void setExternalDocs(ExternalDocs externalDocs)
{
this.externalDocs = externalDocs;
}
/*******************************************************************************
** Fluent setter for externalDocs
*******************************************************************************/
public OpenAPI withExternalDocs(ExternalDocs externalDocs)
{
this.externalDocs = externalDocs;
return (this);
}
/*******************************************************************************
** Getter for servers
*******************************************************************************/
public List<Server> getServers()
{
return (this.servers);
}
/*******************************************************************************
** Setter for servers
*******************************************************************************/
public void setServers(List<Server> servers)
{
this.servers = servers;
}
/*******************************************************************************
** Fluent setter for servers
*******************************************************************************/
public OpenAPI withServers(List<Server> servers)
{
this.servers = servers;
return (this);
}
/*******************************************************************************
** Getter for tags
*******************************************************************************/
public List<Tag> getTags()
{
return (this.tags);
}
/*******************************************************************************
** Setter for tags
*******************************************************************************/
public void setTags(List<Tag> tags)
{
this.tags = tags;
}
/*******************************************************************************
** Fluent setter for tags
*******************************************************************************/
public OpenAPI withTags(List<Tag> tags)
{
this.tags = tags;
return (this);
}
/*******************************************************************************
** Getter for components
*******************************************************************************/
public Components getComponents()
{
return (this.components);
}
/*******************************************************************************
** Setter for components
*******************************************************************************/
public void setComponents(Components components)
{
this.components = components;
}
/*******************************************************************************
** Fluent setter for components
*******************************************************************************/
public OpenAPI withComponents(Components components)
{
this.components = components;
return (this);
}
/*******************************************************************************
** Getter for paths
*******************************************************************************/
public Map<String, Path> getPaths()
{
return (this.paths);
}
/*******************************************************************************
** Setter for paths
*******************************************************************************/
public void setPaths(Map<String, Path> paths)
{
this.paths = paths;
}
/*******************************************************************************
** Fluent setter for paths
*******************************************************************************/
public OpenAPI withPaths(Map<String, Path> paths)
{
this.paths = paths;
return (this);
}
}

View File

@ -0,0 +1,226 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.Map;
/*******************************************************************************
**
*******************************************************************************/
public class Parameter
{
private String name;
private String description;
private String in;
private Schema schema;
private Boolean explode;
private Map<String, Example> examples;
/*******************************************************************************
** Getter for name
*******************************************************************************/
public String getName()
{
return (this.name);
}
/*******************************************************************************
** Setter for name
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
public Parameter withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Parameter withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for in
*******************************************************************************/
public String getIn()
{
return (this.in);
}
/*******************************************************************************
** Setter for in
*******************************************************************************/
public void setIn(String in)
{
this.in = in;
}
/*******************************************************************************
** Fluent setter for in
*******************************************************************************/
public Parameter withIn(String in)
{
this.in = in;
return (this);
}
/*******************************************************************************
** Getter for schema
*******************************************************************************/
public Schema getSchema()
{
return (this.schema);
}
/*******************************************************************************
** Setter for schema
*******************************************************************************/
public void setSchema(Schema schema)
{
this.schema = schema;
}
/*******************************************************************************
** Fluent setter for schema
*******************************************************************************/
public Parameter withSchema(Schema schema)
{
this.schema = schema;
return (this);
}
/*******************************************************************************
** Getter for explode
*******************************************************************************/
public Boolean getExplode()
{
return (this.explode);
}
/*******************************************************************************
** Setter for explode
*******************************************************************************/
public void setExplode(Boolean explode)
{
this.explode = explode;
}
/*******************************************************************************
** Fluent setter for explode
*******************************************************************************/
public Parameter withExplode(Boolean explode)
{
this.explode = explode;
return (this);
}
/*******************************************************************************
** Getter for examples
*******************************************************************************/
public Map<String, Example> getExamples()
{
return (this.examples);
}
/*******************************************************************************
** Setter for examples
*******************************************************************************/
public void setExamples(Map<String, Example> examples)
{
this.examples = examples;
}
/*******************************************************************************
** Fluent setter for examples
*******************************************************************************/
public Parameter withExamples(Map<String, Example> examples)
{
this.examples = examples;
return (this);
}
}

View File

@ -0,0 +1,191 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Path
{
private Method get;
private Method patch;
private Method put;
private Method delete;
private Method post;
/*******************************************************************************
** Getter for get
*******************************************************************************/
public Method getGet()
{
return (this.get);
}
/*******************************************************************************
** Setter for get
*******************************************************************************/
public void setGet(Method get)
{
this.get = get;
}
/*******************************************************************************
** Fluent setter for get
*******************************************************************************/
public Path withGet(Method get)
{
this.get = get;
return (this);
}
/*******************************************************************************
** Getter for post
*******************************************************************************/
public Method getPost()
{
return (this.post);
}
/*******************************************************************************
** Setter for post
*******************************************************************************/
public void setPost(Method post)
{
this.post = post;
}
/*******************************************************************************
** Fluent setter for post
*******************************************************************************/
public Path withPost(Method post)
{
this.post = post;
return (this);
}
/*******************************************************************************
** Getter for put
*******************************************************************************/
public Method getPut()
{
return (this.put);
}
/*******************************************************************************
** Setter for put
*******************************************************************************/
public void setPut(Method put)
{
this.put = put;
}
/*******************************************************************************
** Fluent setter for put
*******************************************************************************/
public Path withPut(Method put)
{
this.put = put;
return (this);
}
/*******************************************************************************
** Getter for patch
*******************************************************************************/
public Method getPatch()
{
return (this.patch);
}
/*******************************************************************************
** Setter for patch
*******************************************************************************/
public void setPatch(Method patch)
{
this.patch = patch;
}
/*******************************************************************************
** Fluent setter for patch
*******************************************************************************/
public Path withPatch(Method patch)
{
this.patch = patch;
return (this);
}
/*******************************************************************************
** Getter for delete
*******************************************************************************/
public Method getDelete()
{
return (this.delete);
}
/*******************************************************************************
** Setter for delete
*******************************************************************************/
public void setDelete(Method delete)
{
this.delete = delete;
}
/*******************************************************************************
** Fluent setter for delete
*******************************************************************************/
public Path withDelete(Method delete)
{
this.delete = delete;
return (this);
}
}

View File

@ -0,0 +1,31 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Property
{
private String name;
}

View File

@ -0,0 +1,130 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.List;
/*******************************************************************************
**
*******************************************************************************/
public class RequestBody
{
private Boolean required = false;
private String description;
private List<Content> content;
/*******************************************************************************
** Getter for required
*******************************************************************************/
public Boolean getRequired()
{
return (this.required);
}
/*******************************************************************************
** Setter for required
*******************************************************************************/
public void setRequired(Boolean required)
{
this.required = required;
}
/*******************************************************************************
** Fluent setter for required
*******************************************************************************/
public RequestBody withRequired(Boolean required)
{
this.required = required;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public RequestBody withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for content
*******************************************************************************/
public List<Content> getContent()
{
return (this.content);
}
/*******************************************************************************
** Setter for content
*******************************************************************************/
public void setContent(List<Content> content)
{
this.content = content;
}
/*******************************************************************************
** Fluent setter for content
*******************************************************************************/
public RequestBody withContent(List<Content> content)
{
this.content = content;
return (this);
}
}

View File

@ -0,0 +1,132 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonGetter;
/*******************************************************************************
**
*******************************************************************************/
public class Response
{
private String description;
private Map<String, Content> content;
private String ref;
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Response withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for ref
*******************************************************************************/
@JsonGetter("$ref")
public String getRef()
{
return (this.ref);
}
/*******************************************************************************
** Setter for ref
*******************************************************************************/
public void setRef(String ref)
{
this.ref = ref;
}
/*******************************************************************************
** Fluent setter for ref
*******************************************************************************/
public Response withRef(String ref)
{
this.ref = ref;
return (this);
}
/*******************************************************************************
** Getter for content
*******************************************************************************/
public Map<String, Content> getContent()
{
return (this.content);
}
/*******************************************************************************
** Setter for content
*******************************************************************************/
public void setContent(Map<String, Content> content)
{
this.content = content;
}
/*******************************************************************************
** Fluent setter for content
*******************************************************************************/
public Response withContent(Map<String, Content> content)
{
this.content = content;
return (this);
}
}

View File

@ -0,0 +1,294 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonGetter;
/*******************************************************************************
**
*******************************************************************************/
public class Schema
{
private String type;
private String description;
private List<String> enumValues;
private Schema items;
private Map<String, Schema> properties;
private String example;
private String ref;
private List<Schema> allOf;
/*******************************************************************************
** Getter for type
*******************************************************************************/
public String getType()
{
return (this.type);
}
/*******************************************************************************
** Setter for type
*******************************************************************************/
public void setType(String type)
{
this.type = type;
}
/*******************************************************************************
** Fluent setter for type
*******************************************************************************/
public Schema withType(String type)
{
this.type = type;
return (this);
}
/*******************************************************************************
** Getter for items
*******************************************************************************/
public Schema getItems()
{
return (this.items);
}
/*******************************************************************************
** Setter for items
*******************************************************************************/
public void setItems(Schema items)
{
this.items = items;
}
/*******************************************************************************
** Fluent setter for items
*******************************************************************************/
public Schema withItems(Schema items)
{
this.items = items;
return (this);
}
/*******************************************************************************
** Getter for properties
*******************************************************************************/
public Map<String, Schema> getProperties()
{
return (this.properties);
}
/*******************************************************************************
** Setter for properties
*******************************************************************************/
public void setProperties(Map<String, Schema> properties)
{
this.properties = properties;
}
/*******************************************************************************
** Fluent setter for properties
*******************************************************************************/
public Schema withProperties(Map<String, Schema> properties)
{
this.properties = properties;
return (this);
}
/*******************************************************************************
** Getter for example
*******************************************************************************/
public String getExample()
{
return (this.example);
}
/*******************************************************************************
** Setter for example
*******************************************************************************/
public void setExample(String example)
{
this.example = example;
}
/*******************************************************************************
** Fluent setter for example
*******************************************************************************/
public Schema withExample(String example)
{
this.example = example;
return (this);
}
/*******************************************************************************
** Getter for ref
*******************************************************************************/
@JsonGetter("$ref")
public String getRef()
{
return (this.ref);
}
/*******************************************************************************
** Setter for ref
*******************************************************************************/
public void setRef(String ref)
{
this.ref = ref;
}
/*******************************************************************************
** Fluent setter for ref
*******************************************************************************/
public Schema withRef(String ref)
{
this.ref = ref;
return (this);
}
/*******************************************************************************
** Getter for allOf
*******************************************************************************/
public List<Schema> getAllOf()
{
return (this.allOf);
}
/*******************************************************************************
** Setter for allOf
*******************************************************************************/
public void setAllOf(List<Schema> allOf)
{
this.allOf = allOf;
}
/*******************************************************************************
** Fluent setter for allOf
*******************************************************************************/
public Schema withAllOf(List<Schema> allOf)
{
this.allOf = allOf;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Schema withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for enumValues
*******************************************************************************/
@JsonGetter("enum")
public List<String> getEnumValues()
{
return (this.enumValues);
}
/*******************************************************************************
** Setter for enumValues
*******************************************************************************/
public void setEnumValues(List<String> enumValues)
{
this.enumValues = enumValues;
}
/*******************************************************************************
** Fluent setter for enumValues
*******************************************************************************/
public Schema withEnumValues(List<String> enumValues)
{
this.enumValues = enumValues;
return (this);
}
}

View File

@ -0,0 +1,95 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Server
{
private String description;
private String url;
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Server withDescription(String description)
{
this.description = description;
return (this);
}
/*******************************************************************************
** Getter for url
*******************************************************************************/
public String getUrl()
{
return (this.url);
}
/*******************************************************************************
** Setter for url
*******************************************************************************/
public void setUrl(String url)
{
this.url = url;
}
/*******************************************************************************
** Fluent setter for url
*******************************************************************************/
public Server withUrl(String url)
{
this.url = url;
return (this);
}
}

View File

@ -0,0 +1,95 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model.openapi;
/*******************************************************************************
**
*******************************************************************************/
public class Tag
{
private String name;
private String description;
/*******************************************************************************
** Getter for name
*******************************************************************************/
public String getName()
{
return (this.name);
}
/*******************************************************************************
** Setter for name
*******************************************************************************/
public void setName(String name)
{
this.name = name;
}
/*******************************************************************************
** Fluent setter for name
*******************************************************************************/
public Tag withName(String name)
{
this.name = name;
return (this);
}
/*******************************************************************************
** Getter for description
*******************************************************************************/
public String getDescription()
{
return (this.description);
}
/*******************************************************************************
** Setter for description
*******************************************************************************/
public void setDescription(String description)
{
this.description = description;
}
/*******************************************************************************
** Fluent setter for description
*******************************************************************************/
public Tag withDescription(String description)
{
this.description = description;
return (this);
}
}

View File

@ -0,0 +1,25 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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/>.
*/
/*******************************************************************************
** The POJOs in this package represent a model of an OpenAPI spec file.
*******************************************************************************/
package com.kingsrook.qqq.api.model.openapi;

View File

@ -0,0 +1,68 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.actions;
import com.kingsrook.qqq.api.model.APIVersion;
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecInput;
import com.kingsrook.qqq.api.model.actions.GenerateOpenApiSpecOutput;
import com.kingsrook.qqq.api.model.metadata.ApiInstanceMetaData;
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import org.junit.jupiter.api.Test;
/*******************************************************************************
** Unit test for GenerateOpenApiSpecAction
*******************************************************************************/
class GenerateOpenApiSpecActionTest // todo base test
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void test() throws QException
{
String version = "2023.03";
QInstance qInstance = QContext.getQInstance();
qInstance.withMiddlewareMetaData(new ApiInstanceMetaData()
.withCurrentVersion(new APIVersion(version))
);
for(QTableMetaData table : qInstance.getTables().values())
{
table.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion(version));
}
new QInstanceEnricher(qInstance).enrich();
GenerateOpenApiSpecOutput output = new GenerateOpenApiSpecAction().execute(new GenerateOpenApiSpecInput().withVersion(version));
System.out.println(output.getYaml());
}
}

View File

@ -0,0 +1,113 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.actions;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import com.kingsrook.qqq.api.model.actions.GetTableApiFieldsInput;
import com.kingsrook.qqq.api.model.metadata.fields.ApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.fields.RemovedApiFieldMetaData;
import com.kingsrook.qqq.api.model.metadata.tables.ApiTableMetaData;
import com.kingsrook.qqq.backend.core.context.QContext;
import com.kingsrook.qqq.backend.core.exceptions.QException;
import com.kingsrook.qqq.backend.core.instances.QInstanceEnricher;
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 org.junit.jupiter.api.Test;
import static com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType.STRING;
import static org.junit.jupiter.api.Assertions.assertEquals;
/*******************************************************************************
** Unit test for GetTableApiFieldsAction
*******************************************************************************/
class GetTableApiFieldsActionTest // todo base test
{
private final String TABLE_NAME = "testTable";
Function<List<? extends QFieldMetaData>, Set<String>> fieldListToNameSet = l -> l.stream().map(f -> f.getName()).collect(Collectors.toSet());
/*******************************************************************************
**
*******************************************************************************/
private List<? extends QFieldMetaData> getFields(String tableName, String version) throws QException
{
return new GetTableApiFieldsAction().execute(new GetTableApiFieldsInput().withTableName(tableName).withVersion(version)).getFields();
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testAdditions() throws QException
{
QInstance qInstance = QContext.getQInstance();
qInstance.addTable(new QTableMetaData()
.withName(TABLE_NAME)
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("1"))
.withField(new QFieldMetaData("a", STRING)) // inherit versionRange from the table
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1")))
.withField(new QFieldMetaData("c", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("2")))
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("3")))
);
new QInstanceEnricher(qInstance).enrich();
assertEquals(Set.of("a", "b"), fieldListToNameSet.apply(getFields(TABLE_NAME, "1")));
assertEquals(Set.of("a", "b", "c"), fieldListToNameSet.apply(getFields(TABLE_NAME, "2")));
assertEquals(Set.of("a", "b", "c", "d"), fieldListToNameSet.apply(getFields(TABLE_NAME, "3")));
}
/*******************************************************************************
**
*******************************************************************************/
@Test
void testRemoval() throws QException
{
QInstance qInstance = QContext.getQInstance();
qInstance.addTable(new QTableMetaData()
.withName(TABLE_NAME)
.withMiddlewareMetaData(new ApiTableMetaData().withInitialVersion("1")
.withRemovedApiField(((RemovedApiFieldMetaData) new RemovedApiFieldMetaData("d", STRING)
.withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1")))
.withFinalVersion("2"))
)
.withField(new QFieldMetaData("a", STRING)) // inherit versionRange from the table
.withField(new QFieldMetaData("b", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("1")))
.withField(new QFieldMetaData("d", STRING).withMiddlewareMetaData(new ApiFieldMetaData().withInitialVersion("3")))
);
new QInstanceEnricher(qInstance).enrich();
assertEquals(Set.of("a", "b", "d"), fieldListToNameSet.apply(getFields(TABLE_NAME, "1")));
assertEquals(Set.of("a", "b", "d"), fieldListToNameSet.apply(getFields(TABLE_NAME, "2")));
assertEquals(Set.of("a", "b", "c"), fieldListToNameSet.apply(getFields(TABLE_NAME, "3")));
}
}

View File

@ -0,0 +1,70 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
** Unit test for APIVersionRange
*******************************************************************************/
class APIVersionRangeTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void test()
{
assertTrue(APIVersionRange.beforeAndIncluding("2023.Q2").includes(new APIVersion("2023.Q1")));
assertTrue(APIVersionRange.beforeAndIncluding("2023.Q2").includes(new APIVersion("2023.Q2")));
assertFalse(APIVersionRange.beforeAndIncluding("2023.Q2").includes(new APIVersion("2023.Q3")));
assertFalse(APIVersionRange.afterAndIncluding("2023.Q2").includes(new APIVersion("2023.Q1")));
assertTrue(APIVersionRange.afterAndIncluding("2023.Q2").includes(new APIVersion("2023.Q2")));
assertTrue(APIVersionRange.afterAndIncluding("2023.Q2").includes(new APIVersion("2023.Q3")));
assertTrue(APIVersionRange.beforeButExcluding("2023.Q2").includes(new APIVersion("2023.Q1")));
assertFalse(APIVersionRange.beforeButExcluding("2023.Q2").includes(new APIVersion("2023.Q2")));
assertFalse(APIVersionRange.beforeButExcluding("2023.Q2").includes(new APIVersion("2023.Q3")));
assertFalse(APIVersionRange.afterButExcluding("2023.Q2").includes(new APIVersion("2023.Q1")));
assertFalse(APIVersionRange.afterButExcluding("2023.Q2").includes(new APIVersion("2023.Q2")));
assertTrue(APIVersionRange.afterButExcluding("2023.Q2").includes(new APIVersion("2023.Q3")));
assertFalse(APIVersionRange.betweenAndIncluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q1")));
assertTrue(APIVersionRange.betweenAndIncluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q2")));
assertTrue(APIVersionRange.betweenAndIncluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q3")));
assertTrue(APIVersionRange.betweenAndIncluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q4")));
assertFalse(APIVersionRange.betweenAndIncluding("2023.Q2", "2023.Q4").includes(new APIVersion("2024.Q1")));
assertFalse(APIVersionRange.betweenButExcluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q1")));
assertFalse(APIVersionRange.betweenButExcluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q2")));
assertTrue(APIVersionRange.betweenButExcluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q3")));
assertFalse(APIVersionRange.betweenButExcluding("2023.Q2", "2023.Q4").includes(new APIVersion("2023.Q4")));
assertFalse(APIVersionRange.betweenButExcluding("2023.Q2", "2023.Q4").includes(new APIVersion("2024.Q1")));
}
}

View File

@ -0,0 +1,57 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2023. 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.api.model;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
/*******************************************************************************
** Unit test for com.kingsrook.qqq.api.model.metadata.APIVersion
*******************************************************************************/
class APIVersionTest
{
/*******************************************************************************
**
*******************************************************************************/
@Test
void test()
{
assertEquals(0, new APIVersion("1.0.0").compareTo(new APIVersion("1.0.0")));
assertTrue(new APIVersion("10").compareTo(new APIVersion("2")) > 0);
assertTrue(new APIVersion("200").compareTo(new APIVersion("30")) > 0);
assertTrue(new APIVersion("1.0.1").compareTo(new APIVersion("1.0.0")) > 0);
assertTrue(new APIVersion("1.0.10").compareTo(new APIVersion("1.0.0")) > 0);
assertTrue(new APIVersion("0.0.0-2").compareTo(new APIVersion("0.0.0-1")) > 0);
assertTrue(new APIVersion("1.0.0").compareTo(new APIVersion("1.0.1")) < 0);
assertTrue(new APIVersion("1.0.0").compareTo(new APIVersion("1.0.10")) < 0);
assertTrue(new APIVersion("2023.Q1").compareTo(new APIVersion("2023.Q2")) < 0);
assertTrue(new APIVersion("2024.Q1").compareTo(new APIVersion("2023.Q4")) > 0);
}
}

View File

@ -0,0 +1,252 @@
openapi: "3.0.3"
info:
title: "QQQ API"
description: "This is your api description!\n"
termsOfService: "https://swagger.io/terms/"
contact:
email: "apiteam@swagger.io"
license:
name: "Apache 2.0"
url: "https://www.apache.org/licenses/LICENSE-2.0.html"
version: "1.0.11"
externalDocs:
description: "Find out more at:"
url: "https://swagger.io"
servers:
- url: "https://petstore3.swagger.io/api/v3"
tags:
- name: "person"
description: "Operations on the Person table."
- name: "personFile"
description: "Operations on the Person File table."
- name: "personMemory"
description: "Operations on the Person Memory table."
- name: "personMemoryCache"
description: "Operations on the Person Memory Cache table."
- name: "idAndNameOnly"
description: "Operations on the Id and Name Only table."
- name: "shape"
description: "Operations on the Shape table."
- name: "basepullTest"
description: "Operations on the Basepull Test table."
- name: "order"
description: "Operations on the Order table."
- name: "orderLine"
description: "Operations on the Order Line table."
paths:
/person/{id}:
get:
summary: "Find Person by Id"
description: "Returns a single Person"
operationId: "getPersonById"
responses:
"200":
description: "Successfully got Person"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Person to return"
required: true
tags:
- "person"
/personFile/{id}:
get:
summary: "Find Person File by Id"
description: "Returns a single Person File"
operationId: "getPersonFileById"
responses:
"200":
description: "Successfully got Person File"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Person File to return"
required: true
tags:
- "personFile"
/personMemory/{id}:
get:
summary: "Find Person Memory by Id"
description: "Returns a single Person Memory"
operationId: "getPersonMemoryById"
responses:
"200":
description: "Successfully got Person Memory"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Person Memory to return"
required: true
tags:
- "personMemory"
/personMemoryCache/{id}:
get:
summary: "Find Person Memory Cache by Id"
description: "Returns a single Person Memory Cache"
operationId: "getPersonMemoryCacheById"
responses:
"200":
description: "Successfully got Person Memory Cache"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Person Memory Cache to return"
required: true
tags:
- "personMemoryCache"
/idAndNameOnly/{id}:
get:
summary: "Find Id and Name Only by Id"
description: "Returns a single Id and Name Only"
operationId: "getIdAndNameOnlyById"
responses:
"200":
description: "Successfully got Id and Name Only"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Id and Name Only to return"
required: true
tags:
- "idAndNameOnly"
/shape/{id}:
get:
summary: "Find Shape by Id"
description: "Returns a single Shape"
operationId: "getShapeById"
responses:
"200":
description: "Successfully got Shape"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Shape to return"
required: true
tags:
- "shape"
/basepullTest/{id}:
get:
summary: "Find Basepull Test by Id"
description: "Returns a single Basepull Test"
operationId: "getBasepullTestById"
responses:
"200":
description: "Successfully got Basepull Test"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Basepull Test to return"
required: true
tags:
- "basepullTest"
/order/{id}:
get:
summary: "Find Order by Id"
description: "Returns a single Order"
operationId: "getOrderById"
responses:
"200":
description: "Successfully got Order"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Order to return"
required: true
tags:
- "order"
/orderLine/{id}:
get:
summary: "Find Order Line by Id"
description: "Returns a single Order Line"
operationId: "getOrderLineById"
responses:
"200":
description: "Successfully got Order Line"
"401":
description: "Unauthorized. Security credentials were either missing or\
\ invalid."
"403":
description: "Forbidden. The credentials provided do not have permission\
\ to access the requested resource."
parameters:
- schema:
format: "int32"
type: "integer"
in: "path"
name: "id"
description: "Id of Order Line to return"
required: true
tags:
- "orderLine"

View File

@ -0,0 +1,676 @@
info:
title: QQQ API
description: This is your api description!
## termsOfService: https://swagger.io/terms/
contact:
email: contact@kingsrook.com
version: 0.0.1
#externalDocs:
# description: Find out more at
# url: https://swagger.io
servers:
- description: Localhost development
url: http://localhost:8000/api/
tags:
- name: person
description: Operations on the Person table.
paths:
/person/query:
get:
summary: Search the Person table using multiple query string fields.
description: |
Returns Person records matching the query parameters.<br/>
Each query field can be supplied multiple times to add additional criteria.<br/>
Query values can be prefixed with an operator (=, <, <=, >, >=, IN, MATCHES, EMPTY, BETWEEN). The default operator if only a value is given is =.<br/>
Operators can be prefixed with a ! to be negated.<br/>
Operators which are a word (IN, MATCHES, EMPTY, BETWEEN) must be followed by a space.<br/>
Values for operators which take multiple values (IN, BETWEEN) must be comma delimited.<br/>
operationId: queryPerson
tags: [person]
parameters:
- name: pageNo
description: Which page of results to return. Starts at 1.
in: query
schema:
type: integer
- name: pageSize
description: Max number of records to include in a page. Defaults to 50.
in: query
schema:
type: integer
- name: includeCount
in: query
description: |
Whether or not to include the count (total matching records) in the result.<br/>
In some situations, counts can slow down queries, in which case you may want to specify includeCount=false.<br/>
Default is true.<br/>
schema:
type: boolean
- name: booleanOperator
in: query
description: Whether to join query field as an AND or an OR. Default is AND.
schema:
type: string
enum: ["AND", "OR"]
- name: orderBy
in: query
schema:
type: string
examples:
id:
summary: order by id (by default, is ascending)
value: id
idDesc:
summary: order by id descending
value: id asc
idAsc:
summary: order by id ascending (explicitly specified)
value: id asc
stateCity:
summary: order by state, then by city (both ascending)
value: state, city
ratingPriceSku:
summary: rating descending, then price ascending, then sku
value: rating desc, price asc, sku
- name: id
in: query
description: Query on the id field. Can prefix value with an operator, else defaults to = (equals).
schema:
type: array
items:
type: string
explode: true
examples:
equals47:
$ref: "#/components/examples/equals47"
between42and47:
$ref: "#/components/examples/between42and47"
multiple:
$ref: "#/components/examples/multipleNumbers"
- name: firstName
in: query
description: Query on the firstName field. Can prefix value with an operator, else defaults to = (equals).
schema:
type: array
items:
type: string
examples:
equalsJohn:
$ref: "#/components/examples/equalsJohn"
inJohnPaul:
$ref: "#/components/examples/inJohnPaul"
multipleStrings:
$ref: "#/components/examples/multipleStrings"
explode: true
- name: lastName
in: query
description: Query on the lastName field. Can prefix value with an operator, else defaults to = (equals).
schema:
type: array
items:
type: string
examples:
equalsJohn:
$ref: "#/components/examples/equalsJohn"
inJohnPaul:
$ref: "#/components/examples/inJohnPaul"
multipleStrings:
$ref: "#/components/examples/multipleStrings"
explode: true
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/personSearchResult"
description: Successfully searched Person table (though may have found 0 records).
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
post:
summary: Search the Person table using a posted query object
description: |
Returns Person records matching the query parameters.
operationId: queryPerson
tags: [person]
requestBody:
required: true
description: |
List of search fields from the person table.
Each field must include its operator, and per operator, 0 or more values, always specified as an array.
Fields may appear multiple times. All fields will be combined using the specified (query parameter) booleanOperator.
content:
application/json:
schema:
type: object
properties:
booleanOperator:
description: Whether to join query field as an AND or an OR. Default is AND.
type: string
enum: ["AND", "OR"]
criteria:
type: array
items:
type: object
properties:
fieldName:
type: string
operator:
type: string
enum: [EQUALS, NOT_EQUALS, etc]
values:
type: array
items:
type: string
## todo - subfilters!!
example:
- fieldName: firstName
operator: EQUALS
values: ["John"]
- fieldName: id
operator: IN
values: [1,2,3]
parameters:
- name: pageNo
description: Which page of results to return. Starts at 1.
in: query
schema:
type: integer
- name: pageSize
description: Max number of records to include in a page. Defaults to 50.
in: query
schema:
type: integer
- name: includeCount
in: query
description: |
Whether or not to include the count (total matching records) in the result.<br/>
In some situations, counts can slow down queries, in which case you may want to specify includeCount=false.<br/>
Default is true.<br/>
schema:
type: boolean
- name: booleanOperator
in: query
description: Whether to join query field as an AND or an OR. Default is AND.
schema:
type: string
enum: ["AND", "OR"]
- name: orderBy
in: query
schema:
type: string
examples:
id:
summary: order by id (by default, is ascending)
value: id
idDesc:
summary: order by id descending
value: id asc
idAsc:
summary: order by id ascending (explicitly specified)
value: id asc
stateCity:
summary: order by state, then by city (both ascending)
value: state, city
ratingPriceSku:
summary: rating descending, then price ascending, then sku
value: rating desc, price asc, sku
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/personSearchResult"
description: Successfully searched Person table (though may have found 0 records).
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
## /person/filter:
## get:
## summary: Search the Person table using an OData style $filter parameter
## description: Returns Person records matching the query parameters
## operationId: filterPerson
## responses:
## 200:
## description: Successfully searched Person table (though may have 0 results)
## parameters:
## - name: $filter
## in: query
## schema:
## type: string
## items:
## type: string
## description: OData $filter style query string for Person records. See https://some.com/filter for info
## examples:
## simple:
## summary: id equals 42
## value: id eq 42
## complex:
## summary: id equals 42 and firstName like 'Jo%'
## value: id gt 47 and firstName like 'Jo%'
## tags:
## - person
/person/{id}:
get:
summary: Find Person by Id
description: Returns a single Person
operationId: getPerson
responses:
200:
description: Successfully got Person
content:
application/json:
schema:
$ref: "#/components/schemas/person"
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
404:
$ref: "#/components/responses/404"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
parameters:
- schema:
type: integer
in: path
name: id
description: Id of Person to return
required: true
tags:
- person
patch:
summary: Update one Person
description: Updates one Person record
operationId: updatePerson
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/personWithoutId"
parameters:
- schema:
type: integer
in: path
name: id
description: Id of Person to update
required: true
responses:
200:
description: Successfully updated Person
tags:
- person
delete:
summary: Delete one Person
description: Deletes one Person record
operationId: deletePerson
responses:
200:
description: Successfully deleted Person
tags:
- person
/person/:
post:
summary: Create one Person
description: Creates a single Person record
operationId: createPerson
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/personWithoutId"
responses:
201:
description: Created. The person has been created.
content:
application/json:
schema:
type: object
properties:
id:
type: integer
example: 1701
description: Generated id for the person that was inserted.
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
tags:
- person
/person/bulk:
patch:
summary: Update multiple Person records
description: Update multiple Person records
operationId: bulkUpdatePerson
requestBody:
content:
application/json:
example:
- id: 1701
firstName: John
- id: 1702
lastName: McCartney
schema:
type: array
items:
$ref: "#/components/schemas/person"
responses:
207:
description: Multi-Status. See body for status of individual records.
content:
application/json:
schema:
type: array
items:
type: object
properties:
statusCode:
type: integer
description: HTTP status code for the record at this index.
example: 201
statusMessage:
type: string
description: HTTP status message for the record at this index.
example: Created
id:
type: integer
description: Generated id, if applicable, for the record at this index.
example: 1701
error:
type: string
description: Additional error details, if applicable, for the record at this index.
example: "Missing required field: firstName"
example:
- statusCode: 200
statusMessage: OK
- statusCode: 400
statusMessage: Bad Request
error: "Record cannot be deleted due to foreign key check"
- statusCode: 500
statusMessage: Internal Server Error
error: Error connecting to database
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
tags:
- person
delete:
summary: Delete multiple Person records
description: Deletes multiple Person records
operationId: bulkDeletePerson
requestBody:
content:
application/json:
schema:
type: array
items:
type: integer
description: ids of the person records to be deleted
example: [42, 47]
responses:
207:
description: Multi-Status. See body for status of individual records.
content:
application/json:
schema:
type: array
items:
type: object
properties:
statusCode:
type: integer
description: HTTP status code for the record at this index.
example: 201
statusMessage:
type: string
description: HTTP status message for the record at this index.
example: Created
id:
type: integer
description: Generated id, if applicable, for the record at this index.
example: 1701
error:
type: string
description: Additional error details, if applicable, for the record at this index.
example: "Missing required field: firstName"
example:
- statusCode: 201
statusMessage: Created
id: 1701
- statusCode: 400
statusMessage: Bad Request
error: "Missing value for required field: firstName"
- statusCode: 500
statusMessage: Internal Server Error
error: Error connecting to database
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
tags:
- person
post:
summary: Create multiple Person records
description: Creates multiple Person records
operationId: bulkCreatePerson
requestBody:
content:
application/json:
example:
- firstName: John
lastName: Lennon
- firstName: Paul
lastName: McCartney
- firstName: George
lastName: Harrison
schema:
type: array
items:
$ref: "#/components/schemas/personWithoutId"
responses:
207:
description: Multi-Status. See body for status of individual records.
content:
application/json:
schema:
type: array
items:
type: object
properties:
statusCode:
type: integer
description: HTTP status code for the record at this index.
example: 201
statusMessage:
type: string
description: HTTP status message for the record at this index.
example: Created
id:
type: integer
description: Generated id, if applicable, for the record at this index.
example: 1701
error:
type: string
description: Additional error details, if applicable, for the record at this index.
example: "Missing required field: firstName"
example:
- statusCode: 201
statusMessage: Created
id: 1701
- statusCode: 400
statusMessage: Bad Request
error: "Missing value for required field: firstName"
- statusCode: 500
statusMessage: Internal Server Error
error: Error connecting to database
400:
$ref: "#/components/responses/400"
401:
$ref: "#/components/responses/401"
403:
$ref: "#/components/responses/403"
500:
$ref: "#/components/responses/500"
tags:
- person
components:
examples:
equals47:
summary: equal to 47
value:
- "47"
between42and47:
summary: between 42 and 47
value:
- BETWEEN 42,47
multipleNumbers:
summary: between 42 and 47 and not equal to 45
value:
- BETWEEN 42,47
- "!=45"
equalsJohn:
summary: equal to "John"
value:
- "John"
inJohnPaul:
summary: in ("John", "Paul")
value:
- IN ("John","Paul")
multipleStrings:
summary: matches R* and is not Ringo
value:
- MATCHES R*
- "!=Ringo"
schemas:
personWithoutId:
type: object
properties:
firstName:
type: string
description: First Name of the person.
example: John
lastName:
type: string
description: Last Name of the person.
example: Lennon
person:
type: object
properties:
id:
type: integer
description: Id for the person. Primary Key.
example: 47
allOf:
- $ref: "#/components/schemas/personWithoutId"
city:
type: object
properties:
id:
type: integer
description: Id for the city. Primary Key.
example: 47
state:
type: string
description: State of the city.
example: MO
# allOf:
# - $ref: "#/components/schemas/personWithoutId"
baseSearchResultFields:
type: object
properties:
count:
type: integer
description: Number of records that matched the search criteria
pageNo:
type: integer
description: ...
pageSize:
type: integer
description: ...
personSearchResult:
type: object
allOf:
- $ref: "#/components/schemas/baseSearchResultFields"
properties:
records:
type: array
items:
allOf:
- $ref: "#/components/schemas/person"
- $ref: "#/components/schemas/personWithoutId"
responses:
401:
description: Unauthorized. The required authentication credentials were missing or invalid.
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: The required authentication credentials were missing or invalid.
403:
description: Forbidden. You do not have permission to access the requested resource.
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: Forbidden. You do not have permission to access the requested resource.
404:
description: Not Found. The requested record was not found.
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: Not Found. The requested record was not found.
400:
description: Bad Request. Some portion of the request's content was not acceptable to the server. See error message in body for details.
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: 'Parameter id should be given an integer value, but received string: "Foo"'
500:
description: Internal Server Error. An error occurred in the server processing the request.
content:
application/json:
schema:
type: object
properties:
error:
type: string
example: Database connection error. Try again later.

File diff suppressed because it is too large Load Diff