All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.camel.openapi.OpenApiRestProducerFactory Maven / Gradle / Ivy

There is a newer version: 4.8.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.camel.openapi;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;

import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
import org.apache.camel.CamelContext;
import org.apache.camel.Producer;
import org.apache.camel.spi.RestConfiguration;
import org.apache.camel.spi.RestProducerFactory;
import org.apache.camel.support.CamelContextHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OpenApiRestProducerFactory implements RestProducerFactory {

    private static final Logger LOG = LoggerFactory.getLogger(OpenApiRestProducerFactory.class);

    @Override
    public Producer createProducer(
            CamelContext camelContext, String host,
            String verb, String basePath, String uriTemplate, String queryParameters,
            String consumes, String produces, RestConfiguration configuration, Map parameters)
            throws Exception {

        String apiDoc = (String) parameters.get("apiDoc");
        // load json model
        if (apiDoc == null) {
            throw new IllegalArgumentException("OpenApi api-doc must be configured using the apiDoc option");
        }

        String path = uriTemplate != null ? uriTemplate : basePath;
        // path must start with a leading slash
        if (!path.startsWith("/")) {
            path = "/" + path;
        }

        OpenAPI openApi = loadOpenApiModel(apiDoc);
        Operation operation = getOpenApiOperation(openApi, verb, path);
        if (operation == null) {
            throw new IllegalArgumentException("OpenApi api-doc does not contain operation for " + verb + ":" + path);
        }

        // validate if we have the query parameters also
        if (queryParameters != null) {
            for (Parameter param : operation.getParameters()) {
                if ("query".equals(param.getIn()) && Boolean.TRUE.equals(param.getRequired())) {
                    // check if we have the required query parameter defined
                    String key = param.getName();
                    String token = key + "=";
                    boolean hasQuery = queryParameters.contains(token);
                    if (!hasQuery) {
                        throw new IllegalArgumentException(
                                "OpenApi api-doc does not contain query parameter " + key + " for " + verb + ":" + path);
                    }
                }
            }
        }

        String componentName = (String) parameters.get("componentName");

        return createHttpProducer(camelContext, openApi, operation, host, verb, path, queryParameters,
                produces, consumes, componentName, parameters);
    }

    OpenAPI loadOpenApiModel(String apiDoc) throws Exception {
        final OpenAPIParser openApiParser = new OpenAPIParser();
        final SwaggerParseResult openApi = openApiParser.readLocation(apiDoc, null, null);

        if (openApi != null && openApi.getOpenAPI() != null) {
            //   checkV2specification(openApi.getOpenAPI(), uri);
            return openApi.getOpenAPI();
        }

        // In theory there should be a message in the parse result but it has disappeared...
        throw new IllegalArgumentException(
                "The given OpenApi specification could not be loaded from `" + apiDoc + "`.");

    }

    private Operation getOpenApiOperation(OpenAPI openApi, String verb, String path) {
        // path may include base path so skip that
        String basePath = RestOpenApiSupport.getBasePathFromOasDocument(openApi);
        if (basePath != null && path.startsWith(basePath)) {
            path = path.substring(basePath.length());
        }

        PathItem modelPath = openApi.getPaths().get(path);
        if (modelPath == null) {
            return null;
        }

        // get,put,post,head,delete,patch,options
        Operation op = null;
        PathItem.HttpMethod method = PathItem.HttpMethod.valueOf(verb.toUpperCase());
        if (method != null) {
            return modelPath.readOperationsMap().get(method);
        }
        return op;
    }

    private Producer createHttpProducer(
            CamelContext camelContext, OpenAPI openApi, Operation operation,
            String host, String verb, String path, String queryParameters,
            String consumes, String produces,
            String componentName, Map parameters)
            throws Exception {

        LOG.debug("Using OpenApi operation: {} with {} {}", operation, verb, path);

        RestProducerFactory factory = (RestProducerFactory) parameters.remove("restProducerFactory");

        if (factory != null) {
            LOG.debug("Using RestProducerFactory: {}", factory);

            if (produces == null) {
                StringJoiner producesBuilder = new StringJoiner(",");
                List list = new ArrayList<>();
                if (operation.getResponses() != null) {
                    for (ApiResponse response : operation.getResponses().values()) {
                        if (response.getContent() != null) {
                            for (String mediaType : response.getContent().keySet()) {
                                producesBuilder.add(mediaType);
                            }
                        }
                    }
                }
                produces = producesBuilder.length() == 0 ? null : producesBuilder.toString();
            }
            if (consumes == null) {
                StringJoiner consumesBuilder = new StringJoiner(",");
                if (operation.getRequestBody() != null && operation.getRequestBody().getContent() != null) {
                    for (String mediaType : operation.getRequestBody().getContent().keySet()) {
                        consumesBuilder.add(mediaType);
                    }
                }
                consumes = consumesBuilder.length() == 0 ? null : consumesBuilder.toString();
            }

            String basePath;
            String uriTemplate;
            if (host == null) {

                //if no explicit host has been configured then use host and base path from the openApi api-doc
                host = RestOpenApiSupport.getHostFromOasDocument(openApi);
                basePath = RestOpenApiSupport.getBasePathFromOasDocument(openApi);
                uriTemplate = path;

            } else {
                // path includes also uri template
                basePath = path;
                uriTemplate = null;
            }

            RestConfiguration config = CamelContextHelper.getRestConfiguration(camelContext, null, componentName);
            return factory.createProducer(camelContext, host, verb, basePath, uriTemplate, queryParameters, consumes, produces,
                    config, parameters);

        } else {
            throw new IllegalStateException("Cannot find RestProducerFactory in Registry or as a Component to use");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy