My organization has a lot of APIs for different projects. I need an OpenAPI implementation that allows me to create a standalone portal that contains all these APIs (more like a repository) for all our products.
Is there an OpenAPI that supports this?
Another option would be: to be able to merge several instances to a single OpenAPI instance.
There are several ways to implement API catalogs.
Swagger UI (open-source)
Swagger UI 3.0.19+ can display multiple API definitions using the url parameter.
// index.html
const ui = SwaggerUIBundle({
dom_id: '#swagger-ui',
urls: [
{name: "petstore", url: "http://petstore.swagger.io/v2/swagger.json"},
{name: "instagram", url: "https://api.apis.guru/v2/specs/instagram.com/1.0.0/swagger.yaml"}
],
"urls.primaryName": "petstore", // default spec
...
Result:
Since Swagger UI is open source, you can customize its layout and look&feel as your needs dictate.
SwaggerHub (commercial)
SwaggerHub provides API catalog hosting for teams & organizations, either in the cloud or on premises. SwaggerHub also supports API design, collaboration, code generation and workflow integrations among other things.
Disclosure: I work for the company that makes SwaggerHub.
To do that, a great solution is to use SwaggerHub as indicated. However, this tool is not free for private API.
I had the same need, so, to help community in OpenAPI design, I wrote a new tool named "OpenAPI Dev Tool" (in github).
With OpenAPI Dev Tool, we can deploy several documentations (for several use contexts) for Swagger UI / Redoc with hot reload feature, like an SwaggerHub.
It is really easy to use.
Each API is indicated in a configuration file :
{
"folder": "./specs", // Root folder where the specifications are stored
"specs": [ // Array of specifications (several specifications can be exposed)
{ // First specification file
"file": "/petstore.yaml", // Relative path of the specification main file (from "folder" parameter). It has to be an OpenAPI file in YAML or JSON.
"context": { // Object used for template generation (see Template usage chapter below)
...
}
},
{ // Second specification file
"file": "/petstore2.yaml"
...
}
]
}
Then, you can serve the whole API just by hitting npx openapi-dev-tool serve
Open your browser with http://localhost:3000 et voilà :)
Related
I'm using a SpringBoot 2.2.6 WebApplication with Maven 3. I'm also using spring-integration-http for my endpoint, that's mean that my endpoint are similar to follow:
#Bean
public IntegrationFlow test(CommonTransformer<TestDTO, String, TestMapper> testTransformer, Jackson2JsonObjectMapper obj) {
return IntegrationFlows.from(Http.inboundGateway("/foo/{name}")
.requestMapping(m -> m.methods(HttpMethod.GET))
.payloadExpression("#pathVariables.name")
.replyChannel(Constants.REPLY)
.requestPayloadType(String.class))
.transform(testTransformer)
.transform(new ObjectToJsonTransformer(obj))
.channel(Constants.HTTP_REQUEST)
.get();
}
Now I would like to create a OpenApi docs for my endpoint and, if it's possible, a swagger GUI interface to test it.
I have read several official/unofficial docs and I find interesting docs here another much interesting example here.
My preoccupation is that many of this articles are dated before 2020 (for example one of these use deprecated annotation likes #EnableSwagger2Mvc) but I can't managed to find out something more updated.
Is anyone aware of a more up-to-date procedure?
-------------------------- UPDATE --------------------------
First of all Thanks #ArtemBilan for yor response.
Yes I read that article and I'm not new to documenting my REST API. With springdoc-openapi-ui I'm able to create a .json file that, if putted in some editor like http://swagger.io or if used with a specific maven plugin can create a client (in both spring java and Angular language) ready for use.
I have tried the springfox way (above) to documenting my spring-integration-http but it sucks! It generate some useless files to reproduce the call via CURL..
Is not what I'm looking for. I must (the STO asks) documenting my endpoint like the .yaml you can find for the example Swagger Pet Store.
And it seems there's no way with this spring-integration-http to do so..
Any help is appreciate.
Some days ago I started a REST API in JavaEE 7, I implemented a single class with three methods and implemented succesfully Swagger and Swagger-UI in the project, which showed the three endpoints I implemented succesfully in the generated JSON.
However, I migrated to JavaEE 8, and after this change Swagger detects several unknown endpoints, like the "default" ones (this capture shows only part of all of them):
Investigating a bit I discovered that these endpoints may belong to a JPA REST API in Eclipselink implementation, as described here https://oracle-base.com/articles/misc/oracle-rest-data-services-ords-open-api-swagger-support and here https://www.eclipse.org/eclipselink/documentation/2.4/solutions/restful_jpa004.htm#CHDFCFFA
Despite they appear in the generated JSON, all of them contain variable paths, so I can't access them following the path given by Swagger, even inventing some parameters like "version" using the webs above examples.
The Swagger version I use is v3, aka OpenAPI version. I specify OpenAPI properties with #OpenAPIDefinition in the endpoint class, which also contains a #Tag annotation to group them and the three methods contain #Operation tag with their own #ApiResponse. There is no more Swagger/OpenAPI annotations/files/classes written by me.
The question is, how can I make Swagger ignoring these endpoints?
Thanks
Finally I have found a solution. The case is that Swagger scanner engine scans the whole project, ignoring if the class and his methods have #Operation or not. If my hypothesis is true, some Eclipselink classes could have Swagger annotations (I'm not sure), so when Swagger scans, if finds them and add them to the JSON/YAML.
The solution is creating/adding to the existant openapi.yaml (it can have several names and can be in several locations, as enumerated here: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Integration-and-configuration#known-locations) this:
resourceClasses:
- com.path.to.your.package.Resource
prettyPrint: true
cacheTTL: 0
scannerClass: io.swagger.v3.jaxrs2.integration.JaxrsAnnotationScanner
readAllResources: false
Instead of resourceClasses it can be written resourcePackages, and then it should be specified the whole package and the class in the same style as used to specify the package. To be honest, this property does not affect to my problem.
The solution comes on setting readAllResources to false. The reason is here, in a note: https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Annotations#operation
Blockquote
Note: swagger-jaxrs2 reader engine includes by default also methods of scanned resources which are not annotated with #Operation, as long as a jax-rs #Path is defined at class and/or method level, together with the http method annotation (#GET, #POST, etc).
I hope this solution serves for anyone if he/she has to face the same problem.
When attempting to set up swagger, I get the following 'unhandled exception' after navigating to 'swagger/v1/swagger.json':
NotSupportedException: HTTP method "POST" & path "connect/authorize" >overloaded by actions - (references to 3 API)
Actions require unique method/path combination for Swagger 2.0. Use ConflictingActionsResolver as a workaround
This would otherwise be helpful but the root of this issue lies in the fact that this error message is referencing API that are defined within dependencies under the NuGet branch within my VS 2017 project. Is their a way in which I can tell swagger to ignore the API or anything that may resemble API in the projects dependencies branch?
Solution:
Considering that the API is defined within dependency libraries many of the more common solutions i.e [ApiExplorerSettings(IgnoreApi = true)] (tag appended to the API definition) will not suffice.
In order to resolve issues with unique method/path combos when the API are outside of the scope of your project (dependencies) alter the ConfigureServices() method as follows:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "API WSVAP (WebSmartView)", Version = "v1" });
c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());
});
I have a simple question regarding the architecture of my Amazon Simple Workflow / AWS Flow for Ruby app. For background, I have a simple workflow with one activity running in an AWS Flow for Ruby layer on Opsworks. I have a separate REST API running in a Rails App Server layer on Opsworks that I would like to kick off the workflow.
The code in the REST API that kicks off the workflow:
1: domain = AWS::SimpleWorkflow.new.domains['my_domain']
2: workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{from_class: MyWorkflowClass}}
3: workflow_client.start_execution(input_1: #input1, input_2: #input2)
My assumption is that my workflow and REST API code bases could be separate and that the only common component would be the aws-flow Ruby gem and require 'aws/decider'. However, I'm finding that my REST API also needs to have require 'PATH_TO_MY_WORKFLOW_CLASS'. When I remove that line of code from the code file in my REST API that kicks off the workflow, I get the following error:
undefined method `_options' for nil:NilClass; ["/Users/MyName/.rvm/gems/ruby-2.0.0-p247/gems/aws-flow-2.2.1/lib/aws/decider/utilities.rb:183:in `interpret_block_for_options'", "/Users/MyName/.rvm/gems/ruby-2.0.0-p247/gems/aws-flow-2.2.1/lib/aws/decider/implementation.rb:73:in `workflow_client'"
(error at line 2 above)
Am I mistaken? Do I really need to require MyWorkflowClass in my workflow starter app (i.e. my REST API) or am I doing something wrong? I've scoured the documentation and could not find a clear answer to this. All the samples that I can find do indeed have the workflow class included in the workflow starter code, but I'm not sure if it's because they are bundled as a simple sample or if it's because it's the way it's supposed to be. The reason why I am not taking the samples at face value is because requiring the workflow class in the workflow starter code does not make any sense to me. It binds the two apps way too tightly for my taste.
I posted an issue on the aws-flow-ruby sdk and got the answer from an Amazon Engineer. In short, you can use the :from_class option or the :prefix_name and :execution_method options together.
There are two ways of starting the workflow in code
1) Using the aws sdk directly.
In this case, your code doesn't need to know anything about the workflow class. You just need the domain, workflow type (name and version) and the workflow id.
It will look something like -
require 'aws-sdk-v1'
swf = AWS::SimpleWorkflow.new.client
swf.start_workflow_execution(
domain: "HelloWorld",
workflow_type: {
name: "HelloWorldWorkflow",
version: "1.0"
},
workflow_id: "foo",
input: ....,
....other options (optional)...
)
As you can see above, this doesn't require the workflow class at all.
2) Using the aws-flow gem (which is what you are doing above).
There are two ways of using the workflow client provided by the aws-flow gem to start an execution. You can either use the client as a generic client and not tie it to any workflow class or you can use the :from_class option to fetch options from a particular workflow class. To use the from_class option, you need to have the class in the ObjectSpace (hence you need to require the workflow file).
With from_class -
require 'aws/decider'
domain = AWS::SimpleWorkflow.new.domains['my_domain']
workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{from_class: "MyWorkflowClass"}}
workflow_client.start_execution(input_1: #input1, input_2: #input2)
Without from_class -
require 'aws/decider'
domain = AWS::SimpleWorkflow.new.domains['my_domain']
workflow_client = AWS::Flow::workflow_client(domain.client, domain) {{
prefix_name: "YourClassName",
execution_method: "workflow_method_name",
version: "1.0",
...other options...
}}
workflow_client.start_execution(input_1: #input1, input_2: #input2)
The recommended way to start a workflow execution is to use aws-flow WorkflowClient instead of using the SDK directly.
Additional notes with respect to the input accepted by a workflow:
The SDK and the console will only take strings as input. This can be a free form string but if your workflow is written using ruby flow, this string should be a serialized form of your input so that the WorkflowWorker can deserialize the input when it picks up the task and convert it into ruby objects (in this case a hash).
When you use the ruby flow WorkflowClient, the client will automatically serialize your input hash (or any other input) into a string before sending it to SWF. aws-flow by default uses a YAML based data converter to do this (It can be overridden).
If you just want to see what your input hash will look like as a string, you can do the following -
AWS::Flow::FlowConstants.default_data_converter.dump(input_hash)
You can then use this serialized input to start a workflow using the SDK or the console.
Having a master JSON file
{"swaggerVersion":"1.2",
"apiVersion":"1.0",
"apis":[{"path":"/api1"},{"path":"/api2"},{"path":"/api3"},{"path":"/api4"}]}
and JSON files for each of the 4 APIs, which working well with the Swagger library each.
But when I tried to place it all into one JSON file like
{"swaggerVersion":"1.2",
"apiVersion":"1.0",
"apis":[{<api1 json file contents>},{<api2 json file contents>},{<api3 json file contents>},{<api4 json file contents>}]}
it didn't work.
What is proper way to do merge several Swagger v. 1.2 files into a single file?
According to the Swagger 1.2 Specification you just cannot do that.
The "master" JSON file (as you called it) is the Resource Listing of a Swagger API, which just contains an "inventory of the available resources".
The "apis" property of this JSON document is expected be an array of Resource Objects with a specific structure:
{
"path": "/pets",
"description": "Operations about pets."
}
Quoting the API Declaration section of the spec:
The API Declaration provides information about an API exposed on a resource. There should be one file per Resource described. The file MUST be served in the URL described by the path field.
Take a look at the demo application to view all service documentations at a single location: https://github.com/varghgeorge/microservices-single-swagger
Repo shows how to create a springboot application which will serve as a single place for all your springfox/swagger documentations.
Swagger documentation from different services/locations can be configured in this server using yaml config. Details are on the github location.