modules/jooby-apitool/src/main/java/org/jooby/apitool/raml/Raml.java
public static Raml build(Raml base, List<RouteMethod> routes) {
    Raml raml = Optional.ofNullable(base).orElseGet(Raml::new);
    BiFunction<RamlPath, String, RamlPath> pathFactory = (path, segment) ->
        path == null ? raml.path(segment) : path.path(segment);

    BiConsumer<Function<String, RamlParameter>, RouteParameter> parameterFactory = (factory, parameter) -> {
      RamlParameter p = factory.apply(parameter.name());
      p.setDescription(parameter.description()
          .map(Raml::yamlText)
          .orElse(null));
      List<String> enums = parameter.enums();
      if (enums.size() > 0) {
        p.setType(RamlType.STRING);
        p.setEnum(enums);
      } else {
        p.setType(raml.define(parameter.type()));
      }
      p.setRequired(!parameter.optional());
      p.setDefault(parameter.defaultValue());
    };

    /** Default consumes/produces: */
    Set<String> alltypes = new LinkedHashSet<>();
    Consumer<Function<RouteMethod, List<String>>> mediaTypes = types ->
        routes.stream().forEach(r -> types.apply(r).forEach(alltypes::add));
    mediaTypes.accept(RouteMethod::consumes);
    mediaTypes.accept(RouteMethod::produces);
    boolean defaultMediaType = false;
    if (alltypes.size() == 0) {
      raml.setMediaType(ImmutableList.of(MediaType.json.name()));
      defaultMediaType = true;
    } else if (alltypes.size() == 1) {
      raml.setMediaType(ImmutableList.of(alltypes.iterator().next()));
      defaultMediaType = true;
    }

    for (RouteMethod route : routes) {
      List<String> segments = Splitter.on("/")
          .trimResults()
          .omitEmptyStrings()
          .splitToList(route.pattern());
      RamlPath path = null;
      for (String segment : segments) {
        RamlPath newPath = pathFactory.apply(path, "/" + segment);
        if (segment.startsWith("{") && segment.endsWith("}")) {
          String pathvar = segment.substring(1, segment.length() - 1);
          route.parameters().stream()
              .filter(it -> it.kind() == RouteParameter.Kind.PATH)
              .filter(it -> it.name().equals(pathvar))
              .findFirst()
              .ifPresent(it -> parameterFactory.accept(newPath::uriParameter, it));
        }
        path = newPath;
      }
      path = Optional.ofNullable(path).orElseGet(() -> raml.path("/"));
      path.setDescription(route.summary()
          .map(Raml::yamlText)
          .orElse(null));
      RamlMethod method = path.method(route.method());
      method.setDescription(route.description()
          .map(Raml::yamlText)
          .orElse(null));

      /** Check for files, if we find one use multipart to render them: */
      List<RouteParameter> files = route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.FILE)
          .collect(Collectors.toList());
      if (files.size() > 0) {
        route.parameters().stream()
            .filter(it -> it.kind() == RouteParameter.Kind.QUERY)
            .forEach(it -> parameterFactory.accept(method::formParameter, it));
        files.forEach(it -> {
          parameterFactory.accept(method::formParameter, it);
          method.setMediaType(ImmutableList.of(MediaType.multipart.name()));
        });
      } else {
        route.parameters().stream()
            .filter(it -> it.kind() == RouteParameter.Kind.QUERY)
            .forEach(it -> parameterFactory.accept(method::queryParameter, it));
      }
      /** Consumes: */
      List<String> consumes = route.consumes();
      if (consumes.size() == 0 && !defaultMediaType) {
        consumes = ImmutableList.of(MediaType.json.name());
      }
      method.setMediaType(consumes);

      /** Headers: */
      route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.HEADER)
          .forEach(it -> parameterFactory.accept(method::headerParameter, it));

      /** Body: */
      route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.BODY)
          .forEach(it -> {
            method.setMediaType(route.consumes());
            method.setBody(raml.define(it.type()));
          });
      /** Response: */
      List<String> produces = route.produces();
      if (produces.size() == 0) {
        produces = ImmutableList.of(MediaType.json.name());
      }
      RouteResponse returns = route.response();
      Map<Integer, String> status = returns.status();
      Integer statusCode = returns.statusCode();
      RamlResponse response = method.response(statusCode);
      response.setDescription(yamlText(returns.description().orElseGet(() -> FriendlyTypeName
          .name(returns.type()))));
      produces.forEach(type -> response.setMediaType(type, raml.define(returns.type())));
      status.entrySet().stream()
          .filter(it -> !statusCode.equals(it.getKey()))
          .forEach(it -> method.response(it.getKey()).setDescription(it.getValue()));
    }

    return raml;
  }
public static Raml build(Raml base, List<RouteMethod> routes) {
    Raml raml = Optional.ofNullable(base).orElseGet(Raml::new);
    BiFunction<RamlPath, String, RamlPath> pathFactory = (path, segment) ->
        path == null ? raml.path(segment) : path.path(segment);

    BiConsumer<Function<String, RamlParameter>, RouteParameter> parameterFactory = (factory, parameter) -> {
      RamlParameter p = factory.apply(parameter.name());
      p.setDescription(parameter.description()
          .map(Raml::yamlText)
          .orElse(null));
      List<String> enums = parameter.enums();
      if (enums.size() > 0) {
        p.setType(RamlType.STRING);
        p.setEnum(enums);
      } else {
        p.setType(raml.define(parameter.type()));
      }
      p.setRequired(!parameter.optional());
      p.setDefault(parameter.defaultValue());
    };

    /** Default consumes/produces: */
    Set<String> alltypes = new LinkedHashSet<>();
    Consumer<Function<RouteMethod, List<String>>> mediaTypes = types ->
        routes.stream().forEach(r -> types.apply(r).forEach(alltypes::add));
    mediaTypes.accept(RouteMethod::consumes);
    mediaTypes.accept(RouteMethod::produces);
    boolean defaultMediaType = false;
    if (alltypes.size() == 0) {
      raml.setMediaType(ImmutableList.of(MediaType.json.name()));
      defaultMediaType = true;
    } else if (alltypes.size() == 1) {
      raml.setMediaType(ImmutableList.of(alltypes.iterator().next()));
      defaultMediaType = true;
    }

    for (RouteMethod route : routes) {
      List<String> segments = Splitter.on("/")
          .trimResults()
          .omitEmptyStrings()
          .splitToList(route.pattern());
      RamlPath path = null;
      for (String segment : segments) {
        RamlPath newPath = pathFactory.apply(path, "/" + segment);
        if (segment.startsWith("{") && segment.endsWith("}")) {
          String pathvar = segment.substring(1, segment.length() - 1);
          route.parameters().stream()
              .filter(it -> it.kind() == RouteParameter.Kind.PATH)
              .filter(it -> it.name().equals(pathvar))
              .findFirst()
              .ifPresent(it -> parameterFactory.accept(newPath::uriParameter, it));
        }
        path = newPath;
      }
      path = Optional.ofNullable(path).orElseGet(() -> raml.path("/"));
      path.setDescription(route.summary()
          .map(Raml::yamlText)
          .orElse(null));
      RamlMethod method = path.method(route.method());
      method.setDescription(route.description()
          .map(Raml::yamlText)
          .orElse(null));

      /** Check for files, if we find one use multipart to render them: */
      List<RouteParameter> files = route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.FILE)
          .collect(Collectors.toList());
      if (files.size() > 0) {
        route.parameters().stream()
            .filter(it -> it.kind() == RouteParameter.Kind.QUERY)
            .forEach(it -> parameterFactory.accept(method::formParameter, it));
        files.forEach(it -> {
          parameterFactory.accept(method::formParameter, it);
          method.setMediaType(ImmutableList.of(MediaType.multipart.name()));
        });
      } else {
        route.parameters().stream()
            .filter(it -> it.kind() == RouteParameter.Kind.QUERY)
            .forEach(it -> parameterFactory.accept(method::queryParameter, it));
      }
      /** Consumes: */
      List<String> consumes = route.consumes();
      if (consumes.size() == 0 && !defaultMediaType) {
        consumes = ImmutableList.of(MediaType.json.name());
      }
      method.setMediaType(consumes);

      /** Headers: */
      route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.HEADER)
          .forEach(it -> parameterFactory.accept(method::headerParameter, it));

      /** Body: */
      route.parameters().stream()
          .filter(it -> it.kind() == RouteParameter.Kind.BODY)
          .forEach(it -> {
            method.setMediaType(route.consumes());
            method.setBody(raml.define(it.type()));
          });
      /** Response: */
      List<String> produces = route.produces();
      if (produces.size() == 0) {
        produces = ImmutableList.of(MediaType.json.name());
      }
      RouteResponse returns = route.response();
      Map<Integer, String> status = returns.status();
      Integer statusCode = returns.statusCode();
      RamlResponse response = method.response(statusCode);
      response.setDescription(yamlText(returns.description().orElseGet(() -> FriendlyTypeName
          .name(returns.type()))));
      produces.forEach(type -> response.setMediaType(type, raml.define(returns.type())));
      status.entrySet().stream()
          .filter(it -> !statusCode.equals(it.getKey()))
          .forEach(it -> method.response(it.getKey()).setDescription(it.getValue()));
    }

    return raml;
  }
public static Raml build ( Raml base , List < RouteMethod > routes ) { Raml raml = Optional . ofNullable ( base ) . orElseGet ( Raml :: new ) ; BiFunction < RamlPath , String , RamlPath > pathFactory = ( path , segment ) -> path == null ? raml . path ( segment ) : path . path ( segment ) ; BiConsumer < Function < String , RamlParameter > , RouteParameter > parameterFactory = ( factory , parameter ) -> { RamlParameter p = factory . apply ( parameter . name ( ) ) ; p . setDescription ( parameter . description ( ) . map ( Raml :: yamlText ) . orElse ( null ) ) ; List < String > enums = parameter . enums ( ) ; if ( enums . size ( ) > 0 ) { p . setType ( RamlType . STRING ) ; p . setEnum ( enums ) ; } else { p . setType ( raml . define ( parameter . type ( ) ) ) ; } p . setRequired ( ! parameter . optional ( ) ) ; p . setDefault ( parameter . defaultValue ( ) ) ; } ; /** Default consumes/produces: */ Set < String > alltypes = new LinkedHashSet <> ( ) ; Consumer < Function < RouteMethod , List < String > > > mediaTypes = types -> routes . stream ( ) . forEach ( r -> types . apply ( r ) . forEach ( alltypes :: add ) ) ; mediaTypes . accept ( RouteMethod :: consumes ) ; mediaTypes . accept ( RouteMethod :: produces ) ; boolean defaultMediaType = false ; if ( alltypes . size ( ) == 0 ) { raml . setMediaType ( ImmutableList . of ( MediaType . json . name ( ) ) ) ; defaultMediaType = true ; } else if ( alltypes . size ( ) == 1 ) { raml . setMediaType ( ImmutableList . of ( alltypes . iterator ( ) . next ( ) ) ) ; defaultMediaType = true ; } for ( RouteMethod route : routes ) { List < String > segments = Splitter . on ( "/" ) . trimResults ( ) . omitEmptyStrings ( ) . splitToList ( route . pattern ( ) ) ; RamlPath path = null ; for ( String segment : segments ) { RamlPath newPath = pathFactory . apply ( path , "/" + segment ) ; if ( segment . startsWith ( "{" ) && segment . endsWith ( "}" ) ) { String pathvar = segment . substring ( 1 , segment . length ( ) - 1 ) ; route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . PATH ) . filter ( it -> it . name ( ) . equals ( pathvar ) ) . findFirst ( ) . ifPresent ( it -> parameterFactory . accept ( newPath :: uriParameter , it ) ) ; } path = newPath ; } path = Optional . ofNullable ( path ) . orElseGet ( ( ) -> raml . path ( "/" ) ) ; path . setDescription ( route . summary ( ) . map ( Raml :: yamlText ) . orElse ( null ) ) ; RamlMethod method = path . method ( route . method ( ) ) ; method . setDescription ( route . description ( ) . map ( Raml :: yamlText ) . orElse ( null ) ) ; /** Check for files, if we find one use multipart to render them: */ List < RouteParameter > files = route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . FILE ) . collect ( Collectors . toList ( ) ) ; if ( files . size ( ) > 0 ) { route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . QUERY ) . forEach ( it -> parameterFactory . accept ( method :: formParameter , it ) ) ; files . forEach ( it -> { parameterFactory . accept ( method :: formParameter , it ) ; method . setMediaType ( ImmutableList . of ( MediaType . multipart . name ( ) ) ) ; } ) ; } else { route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . QUERY ) . forEach ( it -> parameterFactory . accept ( method :: queryParameter , it ) ) ; } /** Consumes: */ List < String > consumes = route . consumes ( ) ; if ( consumes . size ( ) == 0 && ! defaultMediaType ) { consumes = ImmutableList . of ( MediaType . json . name ( ) ) ; } method . setMediaType ( consumes ) ; /** Headers: */ route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . HEADER ) . forEach ( it -> parameterFactory . accept ( method :: headerParameter , it ) ) ; /** Body: */ route . parameters ( ) . stream ( ) . filter ( it -> it . kind ( ) == RouteParameter . Kind . BODY ) . forEach ( it -> { method . setMediaType ( route . consumes ( ) ) ; method . setBody ( raml . define ( it . type ( ) ) ) ; } ) ; /** Response: */ List < String > produces = route . produces ( ) ; if ( produces . size ( ) == 0 ) { produces = ImmutableList . of ( MediaType . json . name ( ) ) ; } RouteResponse returns = route . response ( ) ; Map < Integer , String > status = returns . status ( ) ; Integer statusCode = returns . statusCode ( ) ; RamlResponse response = method . response ( statusCode ) ; response . setDescription ( yamlText ( returns . description ( ) . orElseGet ( ( ) -> FriendlyTypeName . name ( returns . type ( ) ) ) ) ) ; produces . forEach ( type -> response . setMediaType ( type , raml . define ( returns . type ( ) ) ) ) ; status . entrySet ( ) . stream ( ) . filter ( it -> ! statusCode . equals ( it . getKey ( ) ) ) . forEach ( it -> method . response ( it . getKey ( ) ) . setDescription ( it . getValue ( ) ) ) ; } return raml ; }
Build a {@link Raml} object from list of {@link RouteMethod}.

@param base Base raml (might be null).
@param routes List of routes.
@return RAML object.
Build a { @link Raml } object from list of { @link RouteMethod } .