<!-- Integration tests will be skipped by default. Could be enabled here or by -DskipITs=false-->
<skipITs>true</skipITs>
+
+ <!-- Swagger version for open api json creation -->
+ <swagger.version>2.2.35</swagger.version>
</properties>
<profiles>
<!-- Docker profile to be used for building docker image and pushing to
<version>1.18.36</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-jaxrs2-jakarta</artifactId>
+ <version>${swagger.version}</version>
+ </dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<classesDirectory>${project.build.outputDirectory}</classesDirectory>
</configuration>
</plugin>
+ <plugin>
+ <groupId>io.swagger.core.v3</groupId>
+ <artifactId>swagger-maven-plugin-jakarta</artifactId>
+ <version>${swagger.version}</version>
+ <executions>
+ <execution>
+ <id>generate-openapi</id>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>resolve</goal>
+ </goals>
+ <configuration>
+ <attachSwaggerArtifact>false</attachSwaggerArtifact>
+ <outputPath>${project.build.directory}/generated-swagger-docs</outputPath>
+ <outputFileName>openapi</outputFileName>
+ <outputFormat>JSON</outputFormat>
+ <resourcePackages>
+ <resourcePackage>org.onap.aai</resourcePackage>
+ </resourcePackages>
+ <prettyPrint>true</prettyPrint>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
</plugins>
</build>
</project>
import org.springframework.core.env.Profiles;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import io.swagger.v3.oas.annotations.OpenAPIDefinition;
+import io.swagger.v3.oas.annotations.info.Info;
+
@EnableWebSecurity
@EnableConfigurationProperties
@SpringBootApplication(
"org.onap.aai.tasks", "org.onap.aai.service", "org.onap.aai.rest", "org.onap.aai.aaf",
"org.onap.aai.aailog", "org.onap.aai.introspection", "org.onap.aai.rest.notification"})
@Configuration
+@OpenAPIDefinition(info = @Info(title = "AAI Traversal APIs", description = "Provides APIs for graph-based traversal of AAI entities and their relationships.", version = "1.0.0"))
public class TraversalApp {
private static final Logger logger = LoggerFactory.getLogger(TraversalApp.class.getName());
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestBody;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
@Path("/cq2gremlin")
+@Tag(name = "Custom Queries", description = "Endpoints for converting custom queries into Gremlin traversals.")
public class CQ2Gremlin extends RESTAPI {
private HttpEntry traversalUriHttpEntry;
}
@PUT
- @Consumes({MediaType.APPLICATION_JSON})
- @Produces({MediaType.APPLICATION_JSON})
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(tags = { "Custom Queries" },
+ summary = "Convert custom query to Gremlin traversal", description = "Converts a custom query definition into a Gremlin traversal string.", operationId = "convertCustomQueryToGremlin")
public Response getC2Qgremlin(@RequestBody Map<String, CustomQueryConfigDTO> content,
@Context HttpHeaders headers, @Context UriInfo info) {
if (content.size() == 0) {
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestBody;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
@Path("/cq2gremlintest")
+@Tag(name = "Custom Query Testing", description = "Endpoints for validating custom queries by executing them against a test graph.")
public class CQ2GremlinTest extends RESTAPI {
private static final Logger LOGGER = LoggerFactory.getLogger(CQ2GremlinTest.class);
}
@PUT
- @Consumes({MediaType.APPLICATION_JSON})
- @Produces({MediaType.APPLICATION_JSON})
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ @Operation(tags = {
+ "Custom Query Testing" }, summary = "Test custom query to Gremlin traversal", description = "Executes a custom query against an in-memory graph and validates the results.", operationId = "testCustomQueryToGremlin")
public Response getC2Qgremlin(@RequestBody CustomQueryTestDTO content,
@Context HttpHeaders headers, @Context UriInfo info) throws AAIException {
if (content == null) {
import com.google.gson.JsonParser;
import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
@Timed
@Path("{version: v[1-9][0-9]*|latest}/query")
+@Tag(name = "Query Consumer", description = "Executes predefined or custom queries on the A&AI graph.")
public class QueryConsumer extends TraversalConsumer {
private QueryProcessorType processorType = QueryProcessorType.LOCAL_GROOVY;
}
@PUT
- @Consumes({MediaType.APPLICATION_JSON})
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Operation(summary = "Execute A&AI Query", description = "Runs a query using start URIs, a query name, or a Gremlin string.", responses = {
+ @ApiResponse(responseCode = "200", description = "Query executed successfully", content = {
+ @Content(mediaType = MediaType.APPLICATION_JSON, schema = @Schema(implementation = String.class)),
+ @Content(mediaType = MediaType.APPLICATION_XML, schema = @Schema(implementation = String.class))
+ }),
+ @ApiResponse(responseCode = "400", description = "Invalid request"),
+ @ApiResponse(responseCode = "404", description = "Query target not found"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response executeQuery(
String content,
@PathParam("version") String versionParam,
import org.springframework.beans.factory.annotation.Value;
import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
@Path("/recents/{version: v[1-9][0-9]*|latest}")
@Timed
+@Tag(name = "Recent Data Queries", description = "Retrieve recently updated nodes within a specified time range.")
public class RecentAPIConsumer extends RESTAPI {
private static final String AAI_3021 = "AAI_3021";
@Autowired
public RecentAPIConsumer(HttpEntry traversalUriHttpEntry, SchemaVersions schemaVersions,
- GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer,
- @Value("${schema.uri.base.path}") String basePath) {
+ GremlinServerSingleton gremlinServerSingleton, XmlFormatTransformer xmlFormatTransformer,
+ @Value("${schema.uri.base.path}") String basePath) {
this.traversalUriHttpEntry = traversalUriHttpEntry;
this.schemaVersions = schemaVersions;
this.gremlinServerSingleton = gremlinServerSingleton;
@GET
@Path("/{nodeType: .+}")
- @Consumes({MediaType.APPLICATION_JSON})
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
+ @Operation(summary = "Get recent data for a given node type", description = "Fetches nodes updated within the given hours or date-time for the specified node type and schema version.", parameters = {
+ @Parameter(name = "version", description = "Schema version or 'latest'", required = true),
+ @Parameter(name = "nodeType", description = "Type of the node to query", required = true),
+ @Parameter(name = "hours", description = "Time range in hours", required = false),
+ @Parameter(name = "date-time", description = "Epoch milliseconds for start time", required = false)
+ }, responses = {
+ @ApiResponse(responseCode = "200", description = "Successful retrieval of recent data"),
+ @ApiResponse(responseCode = "400", description = "Invalid input parameters"),
+ @ApiResponse(responseCode = "404", description = "Node type not found"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response getRecentData(@PathParam("version") String versionParam,
- @PathParam("nodeType") String nodeType, @Context HttpHeaders headers,
- @Context HttpServletRequest req, @Context UriInfo info) {
+ @PathParam("nodeType") String nodeType, @Context HttpHeaders headers,
+ @Context HttpServletRequest req, @Context UriInfo info) {
return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED,
TraversalConstants.AAI_TRAVERSAL_TIMEOUT_APP,
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
/**
* Implements the search subdomain in the REST API. All API calls must include
* X-FromAppId and X-TransactionId in the header.
*
*/
@Path("/search")
+@Tag(name = "Model and Named Queries", description = "Execute pre-defined named queries or model-based operations on the AAI graph.")
public class ModelAndNamedQueryRestProvider extends RESTAPI {
private static final Logger LOGGER =
*/
/* ---------------- Start Named Query --------------------- */
@POST
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path(NAMED_QUERY)
+ @Operation(summary = "Execute a named query", description = "Runs a pre-defined query by name and returns the matching graph data.", parameters = {
+ @Parameter(name = "queryParameters", description = "Named query request parameters in JSON or XML format", in = ParameterIn.DEFAULT, required = true)
+ }, responses = {
+ @ApiResponse(responseCode = "200", description = "Successful execution of the named query"),
+ @ApiResponse(responseCode = "400", description = "Invalid query parameters"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response getNamedQueryResponse(@Context HttpHeaders headers,
@Context HttpServletRequest req, String queryParameters, @Context UriInfo info) {
return runner(TraversalConstants.AAI_TRAVERSAL_TIMEOUT_ENABLED,
*/
/* ---------------- Start Named Query --------------------- */
@POST
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path(MODEL_QUERY)
+ @Operation(summary = "Execute a model query", description = "Runs a query or operation based on a model definition. Supports optional delete action.", parameters = {
+ @Parameter(name = "action", description = "Action to perform. Use DELETE to remove matching data.", required = false),
+ @Parameter(name = "inboundPayload", description = "Model query request payload in JSON or XML format", in = ParameterIn.DEFAULT, required = true)
+ }, responses = {
+ @ApiResponse(responseCode = "200", description = "Successful execution of the model query"),
+ @ApiResponse(responseCode = "400", description = "Invalid request payload or parameters"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response getModelQueryResponse(@Context HttpHeaders headers,
@Context HttpServletRequest req, String inboundPayload, @QueryParam("action") String action,
@Context UriInfo info) {
import org.springframework.beans.factory.annotation.Value;
import io.micrometer.core.annotation.Timed;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
/**
* Implements the search subdomain in the REST API. All API calls must include X-FromAppId and
*/
@Path("/{version: v[1-9][0-9]*|latest}/search")
@Timed
+@Tag(name = "Search", description = "Provides APIs to execute graph search queries including generic and node-specific searches")
public class SearchProvider extends RESTAPI {
private static final Logger LOGGER = LoggerFactory.getLogger(SearchProvider.class);
*/
/* ---------------- Start Generic Query --------------------- */
@GET
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path(GENERIC_QUERY)
+ @Operation(summary = "Execute Generic Graph Query", description = "Runs a generic search in the graph database starting from a given node type, with optional filters and depth constraints.", responses = {
+ @ApiResponse(responseCode = "200", description = "Successful execution of the generic query"),
+ @ApiResponse(responseCode = "400", description = "Invalid query parameters"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response getGenericQueryResponse(@Context HttpHeaders headers,
@Context HttpServletRequest req, @QueryParam("start-node-type") final String startNodeType,
@QueryParam("key") final List<String> startNodeKeyParams,
*/
/* ---------------- Start Nodes Query --------------------- */
@GET
- @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+ @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Path(NODES_QUERY)
+ @Operation(summary = "Execute Nodes Graph Query", description = "Runs a node-specific search in the graph database with optional edge and property filters.", responses = {
+ @ApiResponse(responseCode = "200", description = "Successful execution of the nodes query"),
+ @ApiResponse(responseCode = "400", description = "Invalid query parameters"),
+ @ApiResponse(responseCode = "500", description = "Internal server error")
+ })
public Response getNodesQueryResponse(@Context HttpHeaders headers,
@Context HttpServletRequest req,
@QueryParam("search-node-type") final String searchNodeType,
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
/**
* The Class EchoResponse.
*/
@Path("/util")
@Component
+@Tag(name = "Utility", description = "Provides utility endpoints such as health checks and connectivity verification.")
public class EchoResponse extends RESTAPI {
protected static String authPolicyFunctionName = "util";
@GET
@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
@Path("/echo")
+ @Operation(summary = "Health check and echo", description = "Echoes `X-FromAppId` and `X-TransactionId` headers. If `action` is provided, also checks database connectivity.", parameters = {
+ @Parameter(name = "action", in = ParameterIn.QUERY, description = "Check DB connectivity if present"),
+ @Parameter(name = "X-FromAppId", in = ParameterIn.HEADER, required = true),
+ @Parameter(name = "X-TransactionId", in = ParameterIn.HEADER, required = true)
+ }, responses = {
+ @ApiResponse(responseCode = "200", description = "Healthy"),
+ @ApiResponse(responseCode = "503", description = "DB check failed"),
+ @ApiResponse(responseCode = "500", description = "Internal error")
+ })
public Response echoResult(@Context HttpHeaders headers, @Context HttpServletRequest req,
@QueryParam("action") String myAction) {