Search code examples
javaswaggeropenapi

How can I aggregate paths from multiple completely unrelated OpenAPI files?


I am working on a Maven plugin to package some files that I need along with the JAR file. One of those files is an OpenAPI file named component-descriptor.yaml.

Among other things, the plugin needs to check the component-descriptor.yaml of the project's direct dependencies and "aggregate" the paths specified in those files into the current project's file. (I don't care about any of the other details like info, tags, etc.) These files are completely independent of each other and do not use $ref to refer to each other as described in this question - I cannot use $ref or similar mechanisms because the modules do not depend on each other.

How can I accomplish this goal?

I was able to retrieve the component-descriptor.yaml of all direct dependencies and parse them (individually) using io.swagger. I know I could parse the files into Java objects and concatenate the list of paths into a single object, but how can I then turn that back into an OpenAPI file? I couldn't find any support in Swagger for doing so.


Solution

  • As far as I could find, there isn't any "automatic" way to do this. But I have found a rather straightforward method:

    Step 1: Retrieve the OpenAPI files and parse them into OpenAPI objects.

    You can achieve this using Swagger OpenAPIV3Parser:

    Loop the below code for each fileLocation (OpenAPI YAML file) that you have.

    OpenAPI parseOpenAPI(FileLocation fileLocation) throws MojoFailureException {
        SwaggerParseResult swaggerParseResult = parser.readLocation(fileLocation.getUri().toString(), null, null);
    
        if (null == swaggerParseResult || null == swaggerParseResult.getOpenAPI()) {
            throw new MojoFailureException("Failed to parse the openAPI: " + fileLocation);
        }
    
        return swaggerParseResult.getOpenAPI();
    }
    

    Step 2: Merge the objects

    This step is pretty much as you'd expect, just adding anything I need from the other OpenAPI objects into my main OpenAPI object.

    private OpenAPI aggregateOpenAPI(FileLocation mainopenAPI, List<FileLocation> openAPILocations) throws IOException, MojoFailureException {
    
        OpenAPI projectOpenAPI = getOpenAPIFile(mainopenAPI);
    
        if (projectOpenAPI.getComponents() == null) {
            projectOpenAPI.setComponents(new Components());
        }
    
        for (FileLocation fileLocation: openAPILocations) {
    
            OpenAPI openAPI = getOpenAPIFile(fileLocation);
            openAPI.getPaths().forEach(projectOpenAPI.getPaths()::addPathItem);
            Components components = openAPI.getComponents();
            if (components != null) {
                if (components.getParameters() != null) {
                    components.getParameters().forEach(projectOpenAPI.getComponents()::addParameters);
                }
                if (components.getSchemas() != null) {
                    components.getSchemas().forEach(projectOpenAPI.getComponents()::addSchemas);
                }
            }
        }
        return projectOpenAPI;
    }
    

    Step 3: Parse and write to a file

    When I wrote this question, I was missing that Swagger actually provides the ability to parse an OpenAPI object directly into a YAML or JSON file.

    String yamlOpenAPI = Yaml.pretty(projectOpenAPI);
    // or
    String jsonOpenAPI = Json.pretty(projectOpenAPI);
    
    // Write it into a file (make sure directory and file exist)
    Files.write(Paths.get("path/to/file.yaml"), yamlOpenAPI.getBytes());
    

    Edit:

    Note that you may need to use writeString instead of write to support UTF-8 characters like so:

    Files.writeString(Paths.get("path/to/file.yaml"), yamlOpenAPI);