diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/APISpecification.java b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/APISpecification.java index 6b707c1c2..d1448c6f1 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/APISpecification.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/APISpecification.java @@ -27,8 +27,8 @@ public enum APISpecType { SWAGGER_API_1X_YAML("Swagger 1.x (YAML)", YAML), SWAGGER_API_20("Swagger 2.0", JSON), SWAGGER_API_20_YAML("Swagger 2.0 (YAML)", YAML), - OPEN_API_30("Open API 3.0", JSON), - OPEN_API_30_YAML("Open API 3.0 (YAML)", YAML), + OPEN_API_30("Open API 3.x", JSON), + OPEN_API_30_YAML("Open API 3.x (YAML)", YAML), WSDL_API("WSDL", ".xml"), WADL_API("Web Application Description Language (WADL)", ".wadl"), ODATA_V2("OData V2 (converted to OpenAPI 3.0.1)", METADATA, "Given OData specification is converted into an OpenAPI 3 specification.", diff --git a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/OAS3xSpecification.java b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/OAS3xSpecification.java index 78e93c2ab..ee856a872 100644 --- a/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/OAS3xSpecification.java +++ b/modules/apim-adapter/src/main/java/com/axway/apim/api/specification/OAS3xSpecification.java @@ -154,10 +154,10 @@ public boolean parse(byte[] apiSpecificationContent) { if (this.mapper == null) return false; openApiNode = this.mapper.readTree(apiSpecificationContent); LOG.debug("openapi tag value : {}", openApiNode.get(OPENAPI)); - return openApiNode.has(OPENAPI) && openApiNode.get(OPENAPI).asText().startsWith("3.0."); + return openApiNode.has(OPENAPI) && openApiNode.get(OPENAPI).asText().startsWith("3."); } catch (Exception e) { if (LOG.isDebugEnabled()) { - LOG.error("No OpenAPI 3.0 specification.", e); + LOG.error("No OpenAPI 3.x specification.", e); } return false; } diff --git a/modules/apim-adapter/src/test/java/com/axway/apim/api/specification/APISpecificationFactoryTest.java b/modules/apim-adapter/src/test/java/com/axway/apim/api/specification/APISpecificationFactoryTest.java index 677aa509b..21767f443 100644 --- a/modules/apim-adapter/src/test/java/com/axway/apim/api/specification/APISpecificationFactoryTest.java +++ b/modules/apim-adapter/src/test/java/com/axway/apim/api/specification/APISpecificationFactoryTest.java @@ -7,6 +7,7 @@ import com.axway.apim.lib.CoreParameters; import com.axway.apim.lib.error.AppException; import com.axway.apim.lib.utils.Utils; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.io.IOUtils; import org.apache.http.util.Asserts; @@ -43,6 +44,23 @@ public void getAPISpecificationOpenApi() throws AppException { Assert.assertNotNull(apiSpecification.getApiSpecificationContent()); } + @Test + public void getAPISpecificationOpenApi31() throws AppException { + String specDirPath = classLoader.getResource("com/axway/apim/adapter/spec").getFile(); + APISpecification apiSpecification = APISpecificationFactory.getAPISpecification("openapi31.json", specDirPath, "petstore"); + Assert.assertEquals(APISpecification.APISpecType.valueOf("OPEN_API_30"), apiSpecification.getAPIDefinitionType()); + Assert.assertNotNull(apiSpecification.getDescription()); + Assert.assertNotNull(apiSpecification.getApiSpecificationContent()); + // openapi 3.1 specific attribute + ObjectMapper mapper = apiSpecification.getMapper(); + try { + JsonNode node = mapper.readTree(apiSpecification.getApiSpecificationContent()); + Assert.assertNotNull(node.get("info").get("summary").asText()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + @Test public void getAPISpecificationSwagger2() throws AppException { String specDirPath = classLoader.getResource("com/axway/apim/adapter/spec").getFile(); diff --git a/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/spec/openapi31.json b/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/spec/openapi31.json new file mode 100644 index 000000000..4ca863477 --- /dev/null +++ b/modules/apim-adapter/src/test/resources/com/axway/apim/adapter/spec/openapi31.json @@ -0,0 +1,383 @@ +{ + "openapi" : "3.1.0", + "info" : { + "title" : "Swagger Petstore - OpenAPI 3.1", + "description" : "This is a sample Pet Store Server based on the OpenAPI 3.1 specification.\nYou can find out more about\nSwagger at [http://swagger.io](http://swagger.io).", + "termsOfService" : "http://swagger.io/terms/", + "contact" : { + "email" : "apiteam@swagger.io" + }, + "license" : { + "name" : "Apache 2.0 AND (MIT OR GPL-2.0-only)", + "identifier" : "Apache-2.0 AND (MIT OR GPL-2.0-only)" + }, + "version" : "1.0.7", + "summary" : "Pet Store 3.1", + "x-namespace" : "swagger" + }, + "externalDocs" : { + "description" : "Find out more about Swagger", + "url" : "http://swagger.io" + }, + "servers" : [ { + "url" : "/api/v31" + } ], + "tags" : [ { + "name" : "pet", + "description" : "Everything about your Pets", + "externalDocs" : { + "description" : "Find out more", + "url" : "http://swagger.io" + } + }, { + "name" : "store", + "description" : "Access to Petstore orders", + "externalDocs" : { + "description" : "Find out more about our store", + "url" : "http://swagger.io" + } + }, { + "name" : "user", + "description" : "Operations about user" + } ], + "paths" : { + "/pet" : { + "put" : { + "tags" : [ "pet" ], + "summary" : "Update an existing pet", + "description" : "Update an existing pet by Id", + "operationId" : "updatePet", + "requestBody" : { + "description" : "Pet object that needs to be updated in the store", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in JSON Format", + "required" : [ "id" ], + "writeOnly" : true + } + }, + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in XML Format", + "required" : [ "id" ], + "writeOnly" : true + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "description" : "Successful operation", + "content" : { + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in XML Format", + "readOnly" : true + } + }, + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in JSON Format", + "readOnly" : true + } + } + } + }, + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Pet not found" + }, + "405" : { + "description" : "Validation exception" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + }, + "post" : { + "tags" : [ "pet" ], + "summary" : "Add a new pet to the store", + "description" : "Add a new pet to the store", + "operationId" : "addPet", + "requestBody" : { + "description" : "Create a new pet in the store", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in JSON Format", + "required" : [ "id" ], + "writeOnly" : true + } + }, + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in XML Format", + "required" : [ "id" ], + "writeOnly" : true + } + } + }, + "required" : true + }, + "responses" : { + "200" : { + "description" : "Successful operation", + "content" : { + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in XML Format", + "readOnly" : true + } + }, + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in JSON Format", + "readOnly" : true + } + } + } + }, + "405" : { + "description" : "Invalid input" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + } ] + } + }, + "/pet/{petId}" : { + "get" : { + "tags" : [ "pets" ], + "summary" : "Find pet by ID", + "description" : "Returns a pet when 0 < ID <= 10. ID > 10 or nonintegers will simulate API error conditions", + "operationId" : "getPetById", + "parameters" : [ { + "name" : "petId", + "in" : "path", + "description" : "ID of pet that needs to be fetched", + "required" : true, + "schema" : { + "type" : "integer", + "format" : "int64", + "description" : "param ID of pet that needs to be fetched", + "exclusiveMaximum" : 10, + "exclusiveMinimum" : 1 + } + } ], + "responses" : { + "default" : { + "description" : "The pet", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in JSON format" + } + }, + "application/xml" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "A Pet in XML format" + } + } + } + }, + "400" : { + "description" : "Invalid ID supplied" + }, + "404" : { + "description" : "Pet not found" + } + }, + "security" : [ { + "petstore_auth" : [ "write:pets", "read:pets" ] + }, { + "api_key" : [ ] + } ] + } + } + }, + "components" : { + "schemas" : { + "Category" : { + "$id" : "/api/v31/components/schemas/category", + "description" : "Category", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64", + "example" : 1 + }, + "name" : { + "type" : "string", + "example" : "Dogs" + } + }, + "xml" : { + "name" : "Category" + } + }, + "Pet" : { + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "description" : "Pet", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64", + "example" : 10 + }, + "category" : { + "$ref" : "#/components/schemas/Category", + "description" : "Pet Category" + }, + "name" : { + "type" : "string", + "example" : "doggie" + }, + "photoUrls" : { + "type" : "array", + "items" : { + "type" : "string", + "xml" : { + "name" : "photoUrl" + } + }, + "xml" : { + "wrapped" : true + } + }, + "tags" : { + "type" : "array", + "items" : { + "$ref" : "#/components/schemas/Tag" + }, + "xml" : { + "wrapped" : true + } + }, + "status" : { + "type" : "string", + "description" : "pet status in the store", + "enum" : [ "available", "pending", "sold" ] + }, + "availableInstances" : { + "type" : "integer", + "format" : "int32", + "example" : 7, + "exclusiveMaximum" : 10, + "exclusiveMinimum" : 1, + "swagger-extension" : true + }, + "petDetailsId" : { + "type" : "integer", + "format" : "int64", + "$ref" : "#/components/schemas/PetDetails/properties/id" + }, + "petDetails" : { + "$ref" : "#/components/schemas/PetDetails" + } + }, + "required" : [ "name", "photoUrls" ], + "xml" : { + "name" : "Pet" + } + }, + "PetDetails" : { + "$id" : "/api/v31/components/schemas/petdetails", + "$schema" : "https://json-schema.org/draft/2020-12/schema", + "$vocabulary" : "https://spec.openapis.org/oas/3.1/schema-base", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64", + "$anchor" : "pet_details_id", + "example" : 10 + }, + "category" : { + "$ref" : "#/components/schemas/Category", + "description" : "PetDetails Category" + }, + "tag" : { + "$ref" : "#/components/schemas/Tag" + } + }, + "xml" : { + "name" : "PetDetails" + } + }, + "Tag" : { + "$id" : "/api/v31/components/schemas/tag", + "properties" : { + "id" : { + "type" : "integer", + "format" : "int64" + }, + "name" : { + "type" : "string" + } + }, + "xml" : { + "name" : "Tag" + } + } + }, + "securitySchemes" : { + "petstore_auth" : { + "type" : "oauth2", + "flows" : { + "implicit" : { + "authorizationUrl" : "https://petstore3.swagger.io/oauth/authorize", + "scopes" : { + "write:pets" : "modify pets in your account", + "read:pets" : "read your pets" + } + } + } + }, + "mutual_tls" : { + "type" : "mutualTLS" + }, + "api_key" : { + "type" : "apiKey", + "name" : "api_key", + "in" : "header" + } + } + }, + "webhooks" : { + "newPet" : { + "post" : { + "requestBody" : { + "description" : "Information about a new pet in the system", + "content" : { + "application/json" : { + "schema" : { + "$ref" : "#/components/schemas/Pet", + "description" : "Webhook Pet" + } + } + } + }, + "responses" : { + "200" : { + "description" : "Return a 200 status to indicate that the data was received successfully" + } + } + } + } + } +} \ No newline at end of file