Example #1
0
  void appendServicePath(final ObjectSpecification objectSpec) {

    final String serviceId = serviceIdFor(objectSpec);

    final Path path = new Path();
    swagger.path(String.format("/services/%s", serviceId), path);

    final String serviceModelDefinition = serviceId + "Repr";

    final String tag = tagFor(serviceId, "> services");
    path.get(
        new Operation()
            .tag(tag)
            .description(Util.roSpec("15.1"))
            .produces("application/json")
            .produces("application/json;profile=urn:org.restfulobjects:repr-types/object")
            .response(
                200,
                newResponse(Caching.TRANSACTIONAL)
                    .description("OK")
                    .schema(newRefProperty(serviceModelDefinition))));

    final ModelImpl model =
        newModel(Util.roSpec("15.1.2") + ": representation of " + serviceId)
            .property("title", stringProperty())
            .property("serviceId", stringProperty()._default(serviceId))
            .property("members", new ObjectProperty());

    addDefinition(serviceModelDefinition, model);
  }
Example #2
0
  void appendCollectionTo(
      final ObjectSpecification objectSpec, final OneToManyAssociation collection) {

    final String objectType = objectTypeFor(objectSpec);
    final String collectionId = collection.getId();

    final Path path = new Path();
    swagger.path(
        String.format("/objects/%s/{objectId}/collections/%s", objectType, collectionId), path);

    final String tag = tagFor(objectType, null);
    final Operation collectionOperation =
        new Operation()
            .tag(tag)
            .description(Util.roSpec("17.1") + ": resource of " + objectType + "#" + collectionId)
            .parameter(new PathParameter().name("objectId").type("string"))
            .produces("application/json;profile=urn:org.apache.isis/v1")
            .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
            .produces(
                "application/json;profile=urn:org.restfulobjects:repr-types/object-collection");

    path.get(collectionOperation);
    collectionOperation.response(
        200,
        new Response()
            .description(
                objectType
                    + "#"
                    + collectionId
                    + " , if Accept: application/json;profile=urn:org.apache.isis/v1")
            .schema(modelFor(collection)));
  }
  @Override
  public void preprocessSwagger(Swagger swagger) {
    if (swagger != null && swagger.getPaths() != null) {
      for (String pathname : swagger.getPaths().keySet()) {
        Path path = swagger.getPath(pathname);
        if (path.getOperations() != null) {
          for (Operation operation : path.getOperations()) {
            boolean hasFormParameters = false;
            for (Parameter parameter : operation.getParameters()) {
              if (parameter instanceof FormParameter) {
                hasFormParameters = true;
              }
            }

            String defaultContentType =
                hasFormParameters ? "application/x-www-form-urlencoded" : "application/json";
            String contentType =
                operation.getConsumes() == null || operation.getConsumes().isEmpty()
                    ? defaultContentType
                    : operation.getConsumes().get(0);
            String accepts = getAccept(operation);
            operation.setVendorExtension("x-contentType", contentType);
            operation.setVendorExtension("x-accepts", accepts);
          }
        }
      }
    }
  }
Example #4
0
  ModelImpl appendObjectPathAndModelDefinitions(final ObjectSpecification objectSpec) {

    final String objectType = objectTypeFor(objectSpec);

    final Path path = new Path();
    swagger.path(String.format("/objects/%s/{objectId}", objectType), path);

    final String tag = tagFor(objectType, null);
    final Operation operation = new Operation();
    path.get(operation);
    operation
        .tag(tag)
        .description(Util.roSpec("14.1"))
        .parameter(new PathParameter().name("objectId").type("string"))
        .produces("application/json;profile=urn:org.apache.isis/v1")
        .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
        .produces("application/json;profile=urn:org.restfulobjects:repr-types/object");

    // per https://github.com/swagger-api/swagger-spec/issues/146, swagger 2.0 doesn't support
    // multiple
    // modelled representations per path and response code;
    // in particular cannot associate representation/model with Accept header ('produces(...)
    // method)
    final String restfulObjectsModelDefinition = objectType + "RestfulObjectsRepr";
    if (false) {
      operation.response(
          200,
          newResponse(Caching.TRANSACTIONAL)
              .description(
                  "if Accept: application/json;profile=urn:org.restfulobjects:repr-types/object")
              .schema(newRefProperty(restfulObjectsModelDefinition)));

      final ModelImpl roSpecModel =
          newModel(Util.roSpec("14.4") + ": representation of " + objectType)
              .property("title", stringProperty())
              .property("domainType", stringProperty()._default(objectType))
              .property("instanceId", stringProperty())
              .property("members", new ObjectProperty());
      swagger.addDefinition(restfulObjectsModelDefinition, roSpecModel);
    }

    final String isisModelDefinition = objectType + "Repr";
    operation.response(
        200,
        newResponse(Caching.TRANSACTIONAL)
            .description(
                objectType + " , if Accept: application/json;profile=urn:org.apache.isis/v1")
            .schema(newRefProperty(isisModelDefinition)));

    final ModelImpl isisModel = new ModelImpl();
    addDefinition(isisModelDefinition, isisModel);

    // return so can be appended to
    return isisModel;
  }
  public Map<String, List<CodegenOperation>> processPaths(Map<String, Path> paths) {
    Map<String, List<CodegenOperation>> ops = new HashMap<String, List<CodegenOperation>>();

    for (String resourcePath : paths.keySet()) {
      Path path = paths.get(resourcePath);
      processOperation(resourcePath, "get", path.getGet(), ops, path);
      processOperation(resourcePath, "head", path.getHead(), ops, path);
      processOperation(resourcePath, "put", path.getPut(), ops, path);
      processOperation(resourcePath, "post", path.getPost(), ops, path);
      processOperation(resourcePath, "delete", path.getDelete(), ops, path);
      processOperation(resourcePath, "patch", path.getPatch(), ops, path);
      processOperation(resourcePath, "options", path.getOptions(), ops, path);
    }
    return ops;
  }
  private void assertSwagger(Swagger swagger) {
    assertEquals("/", swagger.getBasePath());

    assertEquals(INFO_DESCRIPTION, swagger.getInfo().getDescription());
    assertEquals(INFO_TERMS_OF_SERVICE, swagger.getInfo().getTermsOfService());

    // excluded prefixes
    assertNull(swagger.getPath(ServiceUriPaths.CORE_AUTHZ_USERS));
    assertNull(swagger.getPath(ServiceUriPaths.CORE_AUTHZ_ROLES));

    assertNotNull(swagger.getPath(ServiceUriPaths.CORE_PROCESSES));
    assertNotNull(swagger.getPath(ServiceUriPaths.CORE_CREDENTIALS));

    Path p = swagger.getPath("/cars");
    assertNotNull(p);
    assertNotNull(p.getPost());
    assertNotNull(p.getGet());

    assertNotNull(swagger.getPath("/cars/template"));
    assertNotNull(swagger.getPath("/cars/available"));
    assertNotNull(swagger.getPath("/cars/config"));
    assertNotNull(swagger.getPath("/cars/stats"));
    assertNotNull(swagger.getPath("/cars/subscriptions"));

    assertNotNull(swagger.getPath("/cars/{id}/template"));
    assertNotNull(swagger.getPath("/cars/{id}/available"));
    assertNotNull(swagger.getPath("/cars/{id}/config"));
    assertNotNull(swagger.getPath("/cars/{id}/stats"));
    assertNotNull(swagger.getPath("/cars/{id}/subscriptions"));

    p = swagger.getPath("/cars/{id}");
    assertNotNull(p);
    assertNull(p.getPost());
    assertNull(p.getPatch());
    assertNotNull(p.getGet());
    assertNotNull(p.getPut());

    p = swagger.getPath("/tokens");
    assertNotNull(p);
    assertNotNull(p.getGet());
    assertNotNull(p.getGet().getResponses());
    assertNotNull(p.getPost());
    assertNotNull(p.getPost().getParameters());
    assertNull(p.getPatch());
    assertNull(p.getDelete());

    Model model = swagger.getDefinitions().get(Utils.buildKind(UserToken.class));
    Map<String, Property> properties = model.getProperties();
    assertNull(properties.get(UserToken.FIELD_NAME_INTERNAL_ID));
  }
Example #7
0
  void appendObjectActionInvokePath(
      final ObjectSpecification objectSpec, final ObjectAction objectAction) {

    final String objectType = objectTypeFor(objectSpec);
    final String actionId = objectAction.getId();

    final List<ObjectActionParameter> parameters = objectAction.getParameters();
    final Path path = new Path();
    swagger.path(
        String.format("/objects/%s/{objectId}/actions/%s/invoke", objectType, actionId), path);

    final String tag = tagFor(objectType, null);
    final Operation invokeOperation =
        new Operation()
            .tag(tag)
            .description(
                Util.roSpec("19.1") + ": (invoke) resource of " + objectType + "#" + actionId)
            .parameter(new PathParameter().name("objectId").type("string"))
            .produces("application/json;profile=urn:org.apache.isis/v1")
            .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
            .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result");

    final ActionSemantics.Of semantics = objectAction.getSemantics();
    if (semantics.isSafeInNature()) {
      path.get(invokeOperation);

      for (final ObjectActionParameter parameter : parameters) {
        invokeOperation.parameter(
            new QueryParameter()
                .name(parameter.getId())
                .description(
                    Util.roSpec("2.9.1")
                        + (!Strings.isNullOrEmpty(parameter.getDescription())
                            ? (": " + parameter.getDescription())
                            : ""))
                .required(false)
                .type("string"));
      }
      if (!parameters.isEmpty()) {
        invokeOperation.parameter(
            new QueryParameter()
                .name("x-isis-querystring")
                .description(
                    Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                .required(false)
                .type("string"));
      }

    } else {
      if (semantics.isIdempotentInNature()) {
        path.put(invokeOperation);
      } else {
        path.post(invokeOperation);
      }

      final ModelImpl bodyParam = new ModelImpl().type("object");
      for (final ObjectActionParameter parameter : parameters) {

        final ObjectSpecification specification = parameter.getSpecification();
        final Property valueProperty =
            specification.isValue() ? modelFor(specification) : refToLinkModel();
        bodyParam.property(
            parameter.getId(), new ObjectProperty().property("value", valueProperty));
      }

      invokeOperation
          .consumes("application/json")
          .parameter(new BodyParameter().name("body").schema(bodyParam));
    }

    invokeOperation.response(
        200,
        new Response()
            .description(objectType + "#" + actionId)
            .schema(actionReturnTypeFor(objectAction)));
  }
Example #8
0
  void appendServiceActionInvokePath(
      final ObjectSpecification serviceSpec, final ObjectAction serviceAction) {

    final String serviceId = serviceIdFor(serviceSpec);
    final String actionId = serviceAction.getId();

    final List<ObjectActionParameter> parameters = serviceAction.getParameters();
    final Path path = new Path();
    swagger.path(String.format("/services/%s/actions/%s/invoke", serviceId, actionId), path);

    final String tag = tagFor(serviceId, "> services");
    final Operation invokeOperation =
        new Operation()
            .tag(tag)
            .description(
                Util.roSpec("19.1") + ": (invoke) resource of " + serviceId + "#" + actionId)
            .produces("application/json;profile=urn:org.apache.isis/v1")
            .produces("application/json;profile=urn:org.apache.isis/v1;suppress=true")
            .produces("application/json;profile=urn:org.restfulobjects:repr-types/action-result");

    final ActionSemantics.Of semantics = serviceAction.getSemantics();
    if (semantics.isSafeInNature()) {
      path.get(invokeOperation);

      for (final ObjectActionParameter parameter : parameters) {
        invokeOperation.parameter(
            new QueryParameter()
                .name(parameter.getId())
                .description(
                    Util.roSpec("2.9.1")
                        + (!Strings.isNullOrEmpty(parameter.getDescription())
                            ? (": " + parameter.getDescription())
                            : ""))
                .required(false)
                .type("string"));
      }
      if (!parameters.isEmpty()) {
        invokeOperation.parameter(
            new QueryParameter()
                .name("x-isis-querystring")
                .description(
                    Util.roSpec("2.10") + ": all (formal) arguments as base64 encoded string")
                .required(false)
                .type("string"));
      }

    } else {
      if (semantics.isIdempotentInNature()) {
        path.put(invokeOperation);
      } else {
        path.post(invokeOperation);
      }

      final ModelImpl bodyParam = new ModelImpl().type("object");
      for (final ObjectActionParameter parameter : parameters) {

        final Property valueProperty;
        // TODO: need to switch on parameter's type and create appropriate impl of valueProperty
        // if(parameter.getSpecification().isValue()) ...
        valueProperty = stringProperty();

        bodyParam.property(
            parameter.getId(), new ObjectProperty().property("value", valueProperty));
      }

      invokeOperation
          .consumes("application/json")
          .parameter(new BodyParameter().name("body").schema(bodyParam));
    }

    invokeOperation.response(
        200,
        new Response()
            .description(
                serviceId
                    + "#"
                    + actionId
                    + " , if Accept: application/json;profile=urn:org.apache.isis/v1")
            .schema(actionReturnTypeFor(serviceAction)));
  }
Example #9
0
  public Swagger filter(
      Swagger swagger,
      SwaggerSpecFilter filter,
      Map<String, List<String>> params,
      Map<String, String> cookies,
      Map<String, List<String>> headers) {
    Swagger clone = new Swagger();
    clone
        .info(swagger.getInfo())
        .tags(swagger.getTags() == null ? null : new ArrayList<Tag>(swagger.getTags()))
        .host(swagger.getHost())
        .basePath(swagger.getBasePath())
        .schemes(swagger.getSchemes())
        .consumes(swagger.getConsumes())
        .produces(swagger.getProduces())
        .externalDocs(swagger.getExternalDocs())
        .vendorExtensions(swagger.getVendorExtensions());

    final Set<String> filteredTags = new HashSet<String>();
    final Set<String> allowedTags = new HashSet<String>();
    for (String resourcePath : swagger.getPaths().keySet()) {
      Path path = swagger.getPaths().get(resourcePath);
      Map<String, Operation> ops = new HashMap<String, Operation>();
      ops.put("get", path.getGet());
      ops.put("put", path.getPut());
      ops.put("post", path.getPost());
      ops.put("delete", path.getDelete());
      ops.put("patch", path.getPatch());
      ops.put("options", path.getOptions());

      Path clonedPath = new Path();
      for (String key : ops.keySet()) {
        Operation op = ops.get(key);
        if (op != null) {
          ApiDescription desc = new ApiDescription(resourcePath, key);
          final Set<String> tags;
          if (filter.isOperationAllowed(op, desc, params, cookies, headers)) {
            clonedPath.set(key, filterOperation(filter, op, desc, params, cookies, headers));
            tags = allowedTags;
          } else {
            tags = filteredTags;
          }
          if (op.getTags() != null) {
            tags.addAll(op.getTags());
          }
        }
      }
      if (!clonedPath.isEmpty()) {
        clone.path(resourcePath, clonedPath);
      }
    }
    final List<Tag> tags = clone.getTags();
    filteredTags.removeAll(allowedTags);
    if (tags != null && !filteredTags.isEmpty()) {
      for (Iterator<Tag> it = tags.iterator(); it.hasNext(); ) {
        if (filteredTags.contains(it.next().getName())) {
          it.remove();
        }
      }
      if (clone.getTags().isEmpty()) {
        clone.setTags(null);
      }
    }

    Map<String, Model> definitions =
        filterDefinitions(filter, swagger.getDefinitions(), params, cookies, headers);
    clone.setSecurityDefinitions(swagger.getSecurityDefinitions());
    clone.setDefinitions(definitions);

    // isRemovingUnreferencedDefinitions is not defined in SwaggerSpecFilter to avoid breaking
    // compatibility with
    // existing client filters directly implementing SwaggerSpecFilter.
    if (filter instanceof AbstractSpecFilter) {
      if (((AbstractSpecFilter) filter).isRemovingUnreferencedDefinitions()) {
        clone = removeBrokenReferenceDefinitions(clone);
      }
    }

    return clone;
  }
Example #10
0
  private Swagger removeBrokenReferenceDefinitions(Swagger swagger) {

    if (swagger.getDefinitions() == null || swagger.getDefinitions().isEmpty()) return swagger;

    Set<String> referencedDefinitions = new TreeSet<String>();

    if (swagger.getResponses() != null) {
      for (Response response : swagger.getResponses().values()) {
        String propertyRef = getPropertyRef(response.getSchema());
        if (propertyRef != null) {
          referencedDefinitions.add(propertyRef);
        }
      }
    }
    if (swagger.getParameters() != null) {
      for (Parameter p : swagger.getParameters().values()) {
        if (p instanceof BodyParameter) {
          BodyParameter bp = (BodyParameter) p;
          Set<String> modelRef = getModelRef(bp.getSchema());
          if (modelRef != null) {
            referencedDefinitions.addAll(modelRef);
          }
        }
      }
    }
    if (swagger.getPaths() != null) {
      for (Path path : swagger.getPaths().values()) {
        if (path.getParameters() != null) {
          for (Parameter p : path.getParameters()) {
            if (p instanceof BodyParameter) {
              BodyParameter bp = (BodyParameter) p;
              Set<String> modelRef = getModelRef(bp.getSchema());
              if (modelRef != null) {
                referencedDefinitions.addAll(modelRef);
              }
            }
          }
        }
        if (path.getOperations() != null) {
          for (Operation op : path.getOperations()) {
            if (op.getResponses() != null) {
              for (Response response : op.getResponses().values()) {
                String propertyRef = getPropertyRef(response.getSchema());
                if (propertyRef != null) {
                  referencedDefinitions.add(propertyRef);
                }
              }
            }
            if (op.getParameters() != null) {
              for (Parameter p : op.getParameters()) {
                if (p instanceof BodyParameter) {
                  BodyParameter bp = (BodyParameter) p;
                  Set<String> modelRef = getModelRef(bp.getSchema());
                  if (modelRef != null) {
                    referencedDefinitions.addAll(modelRef);
                  }
                }
              }
            }
          }
        }
      }
    }

    if (swagger.getDefinitions() != null) {
      Set<String> nestedReferencedDefinitions = new TreeSet<String>();
      for (String ref : referencedDefinitions) {
        locateReferencedDefinitions(ref, nestedReferencedDefinitions, swagger);
      }
      referencedDefinitions.addAll(nestedReferencedDefinitions);
      swagger.getDefinitions().keySet().retainAll(referencedDefinitions);
    }

    return swagger;
  }
  public void processOperation(
      String resourcePath,
      String httpMethod,
      Operation operation,
      Map<String, List<CodegenOperation>> operations,
      Path path) {
    if (operation != null) {
      if (System.getProperty("debugOperations") != null) {
        LOGGER.debug(
            "processOperation: resourcePath= "
                + resourcePath
                + "\t;"
                + httpMethod
                + " "
                + operation
                + "\n");
      }
      List<String> tags = operation.getTags();
      if (tags == null) {
        tags = new ArrayList<String>();
        tags.add("default");
      }

      /*
       build up a set of parameter "ids" defined at the operation level
       per the swagger 2.0 spec "A unique parameter is defined by a combination of a name and location"
        i'm assuming "location" == "in"
      */
      Set<String> operationParameters = new HashSet<String>();
      if (operation.getParameters() != null) {
        for (Parameter parameter : operation.getParameters()) {
          operationParameters.add(generateParameterId(parameter));
        }
      }

      // need to propagate path level down to the operation
      if (path.getParameters() != null) {
        for (Parameter parameter : path.getParameters()) {
          // skip propagation if a parameter with the same name is already defined at the operation
          // level
          if (!operationParameters.contains(generateParameterId(parameter))) {
            operation.addParameter(parameter);
          }
        }
      }

      for (String tag : tags) {
        CodegenOperation co = null;
        try {
          co =
              config.fromOperation(
                  resourcePath, httpMethod, operation, swagger.getDefinitions(), swagger);
          co.tags = new ArrayList<String>();
          co.tags.add(sanitizeTag(tag));
          config.addOperationToGroup(sanitizeTag(tag), resourcePath, operation, co, operations);

          List<Map<String, List<String>>> securities = operation.getSecurity();
          if (securities == null && swagger.getSecurity() != null) {
            securities = new ArrayList<Map<String, List<String>>>();
            for (SecurityRequirement sr : swagger.getSecurity()) {
              securities.add(sr.getRequirements());
            }
          }
          if (securities == null || securities.isEmpty()) {
            continue;
          }
          Map<String, SecuritySchemeDefinition> authMethods =
              new HashMap<String, SecuritySchemeDefinition>();
          // NOTE: Use only the first security requirement for now.
          // See the "security" field of "Swagger Object":
          //  https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md#swagger-object
          //  "there is a logical OR between the security requirements"
          if (securities.size() > 1) {
            LOGGER.warn("More than 1 security requirements are found, using only the first one");
          }
          Map<String, List<String>> security = securities.get(0);
          for (String securityName : security.keySet()) {
            SecuritySchemeDefinition securityDefinition = fromSecurity(securityName);
            if (securityDefinition != null) {
              if (securityDefinition instanceof OAuth2Definition) {
                OAuth2Definition oauth2Definition = (OAuth2Definition) securityDefinition;
                OAuth2Definition oauth2Operation = new OAuth2Definition();
                oauth2Operation.setType(oauth2Definition.getType());
                oauth2Operation.setAuthorizationUrl(oauth2Definition.getAuthorizationUrl());
                oauth2Operation.setFlow(oauth2Definition.getFlow());
                oauth2Operation.setTokenUrl(oauth2Definition.getTokenUrl());
                oauth2Operation.setScopes(new HashMap<String, String>());
                for (String scope : security.get(securityName)) {
                  if (oauth2Definition.getScopes().containsKey(scope)) {
                    oauth2Operation.addScope(scope, oauth2Definition.getScopes().get(scope));
                  }
                }
                authMethods.put(securityName, oauth2Operation);
              } else {
                authMethods.put(securityName, securityDefinition);
              }
            }
          }
          if (!authMethods.isEmpty()) {
            co.authMethods = config.fromSecurity(authMethods);
            co.hasAuthMethods = true;
          }
        } catch (Exception ex) {
          String msg =
              "Could not process operation:\n" //
                  + "  Tag: "
                  + tag
                  + "\n" //
                  + "  Operation: "
                  + operation.getOperationId()
                  + "\n" //
                  + "  Resource: "
                  + httpMethod
                  + " "
                  + resourcePath
                  + "\n" //
                  + "  Definitions: "
                  + swagger.getDefinitions()
                  + "\n" //
                  + "  Exception: "
                  + ex.getMessage();
          throw new RuntimeException(msg, ex);
        }
      }
    }
  }
Example #12
0
  private void parse(
      Swagger swagger, RestDefinition rest, String camelContextId, ClassResolver classResolver) {
    List<VerbDefinition> verbs = new ArrayList<>(rest.getVerbs());
    // must sort the verbs by uri so we group them together when an uri has multiple operations
    Collections.sort(verbs, new VerbOrdering());

    // we need to group the operations within the same tag, so use the path as default if not
    // configured
    String pathAsTag =
        rest.getTag() != null ? rest.getTag() : FileUtil.stripLeadingSeparator(rest.getPath());
    String summary = rest.getDescriptionText();

    if (ObjectHelper.isNotEmpty(pathAsTag)) {
      // add rest as tag
      Tag tag = new Tag();
      tag.description(summary);
      tag.name(pathAsTag);
      swagger.addTag(tag);
    }

    // gather all types in use
    Set<String> types = new LinkedHashSet<>();
    for (VerbDefinition verb : verbs) {
      String type = verb.getType();
      if (ObjectHelper.isNotEmpty(type)) {
        if (type.endsWith("[]")) {
          type = type.substring(0, type.length() - 2);
        }
        types.add(type);
      }
      type = verb.getOutType();
      if (ObjectHelper.isNotEmpty(type)) {
        if (type.endsWith("[]")) {
          type = type.substring(0, type.length() - 2);
        }
        types.add(type);
      }
      // there can also be types in response messages
      if (verb.getResponseMsgs() != null) {
        for (RestOperationResponseMsgDefinition def : verb.getResponseMsgs()) {
          type = def.getResponseModel();
          if (ObjectHelper.isNotEmpty(type)) {
            if (type.endsWith("[]")) {
              type = type.substring(0, type.length() - 2);
            }
            types.add(type);
          }
        }
      }
    }

    // use annotation scanner to find models (annotated classes)
    for (String type : types) {
      Class<?> clazz = classResolver.resolveClass(type);
      appendModels(clazz, swagger);
    }

    // used during gathering of apis
    List<Path> paths = new ArrayList<>();

    String basePath = rest.getPath();

    for (VerbDefinition verb : verbs) {

      // the method must be in lower case
      String method = verb.asVerb().toLowerCase(Locale.US);
      // operation path is a key
      String opPath = SwaggerHelper.buildUrl(basePath, verb.getUri());

      Operation op = new Operation();
      if (ObjectHelper.isNotEmpty(pathAsTag)) {
        // group in the same tag
        op.addTag(pathAsTag);
      }

      // add id as vendor extensions
      op.getVendorExtensions().put("x-camelContextId", camelContextId);
      op.getVendorExtensions().put("x-routeId", verb.getRouteId());

      Path path = swagger.getPath(opPath);
      if (path == null) {
        path = new Path();
        paths.add(path);
      }
      path = path.set(method, op);

      String consumes = verb.getConsumes() != null ? verb.getConsumes() : rest.getConsumes();
      if (consumes != null) {
        String[] parts = consumes.split(",");
        for (String part : parts) {
          op.addConsumes(part);
        }
      }

      String produces = verb.getProduces() != null ? verb.getProduces() : rest.getProduces();
      if (produces != null) {
        String[] parts = produces.split(",");
        for (String part : parts) {
          op.addProduces(part);
        }
      }

      if (verb.getDescriptionText() != null) {
        op.summary(verb.getDescriptionText());
      }

      for (RestOperationParamDefinition param : verb.getParams()) {
        Parameter parameter = null;
        if (param.getType().equals(RestParamType.body)) {
          parameter = new BodyParameter();
        } else if (param.getType().equals(RestParamType.form)) {
          parameter = new FormParameter();
        } else if (param.getType().equals(RestParamType.header)) {
          parameter = new HeaderParameter();
        } else if (param.getType().equals(RestParamType.path)) {
          parameter = new PathParameter();
        } else if (param.getType().equals(RestParamType.query)) {
          parameter = new QueryParameter();
        }

        if (parameter != null) {
          parameter.setName(param.getName());
          parameter.setAccess(param.getAccess());
          parameter.setDescription(param.getDescription());
          parameter.setRequired(param.getRequired());

          // set type on parameter
          if (parameter instanceof SerializableParameter) {
            SerializableParameter sp = (SerializableParameter) parameter;

            if (param.getDataType() != null) {
              sp.setType(param.getDataType());
            }
            if (param.getAllowableValues() != null) {
              sp.setEnum(param.getAllowableValues());
            }
          }

          // set schema on body parameter
          if (parameter instanceof BodyParameter) {
            BodyParameter bp = (BodyParameter) parameter;

            if (verb.getType() != null) {
              String ref = modelTypeAsRef(verb.getType(), swagger);
              if (ref != null) {
                bp.setSchema(new RefModel(ref));
              }
            }
          }

          op.addParameter(parameter);
        }
      }

      // if we have an out type then set that as response message
      if (verb.getOutType() != null) {
        Response response = new Response();
        Property prop = modelTypeAsProperty(verb.getOutType(), swagger);
        response.setSchema(prop);
        response.setDescription("Output type");
        op.addResponse("200", response);
      }

      // enrich with configured response messages from the rest-dsl
      for (RestOperationResponseMsgDefinition msg : verb.getResponseMsgs()) {
        Response response = null;
        if (op.getResponses() != null) {
          response = op.getResponses().get(msg.getCode());
        }
        if (response == null) {
          response = new Response();
        }
        if (ObjectHelper.isNotEmpty(msg.getResponseModel())) {
          Property prop = modelTypeAsProperty(msg.getResponseModel(), swagger);
          response.setSchema(prop);
        }
        response.setDescription(msg.getMessage());
        op.addResponse(msg.getCode(), response);
      }

      // add path
      swagger.path(opPath, path);
    }
  }
  public Path path(ObjectNode obj, String location, ParseResult result) {
    boolean hasRef = false;
    Path output = null;
    if (obj.get("$ref") != null) {
      JsonNode ref = obj.get("$ref");
      if (ref.getNodeType().equals(JsonNodeType.STRING)) {
        return pathRef((TextNode) ref, location, result);
      } else if (ref.getNodeType().equals(JsonNodeType.OBJECT)) {
        ObjectNode on = (ObjectNode) ref;

        // extra keys
        Set<String> keys = getKeys(on);
        for (String key : keys) {
          result.extra(location, key, on.get(key));
        }
      }
      return null;
    }
    Path path = new Path();

    ArrayNode parameters = getArray("parameters", obj, false, location, result);
    path.setParameters(parameters(parameters, location, result));

    ObjectNode on = getObject("get", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(get)", result);
      if (op != null) {
        path.setGet(op);
      }
    }
    on = getObject("put", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(put)", result);
      if (op != null) {
        path.setPut(op);
      }
    }
    on = getObject("post", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(post)", result);
      if (op != null) {
        path.setPost(op);
      }
    }
    on = getObject("head", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(head)", result);
      if (op != null) {
        path.setHead(op);
      }
    }
    on = getObject("delete", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(delete)", result);
      if (op != null) {
        path.setDelete(op);
      }
    }
    on = getObject("patch", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(patch)", result);
      if (op != null) {
        path.setPatch(op);
      }
    }
    on = getObject("options", obj, false, location, result);
    if (on != null) {
      Operation op = operation(on, location + "(options)", result);
      if (op != null) {
        path.setOptions(op);
      }
    }

    // extra keys
    Set<String> keys = getKeys(obj);
    for (String key : keys) {
      if (key.startsWith("x-")) {
        path.setVendorExtension(key, extension(obj.get(key)));
      } else if (!PATH_KEYS.contains(key)) {
        result.extra(location, key, obj.get(key));
      }
    }
    return path;
  }