Quantcast

Camel's Swagger vs. Spring MVC Swagger

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Camel's Swagger vs. Spring MVC Swagger

Matt Raible
Hey all,

I'm starting to develop a new application and I'm researching using Camel's REST DSL vs. Spring Boot and it's REST support. The last application I wrote used Apache Camel + Spring Boot, but I only used the external properties support from Boot. For this new application, I have a skeleton of the previous project. The new project needs to do REST (XML-based). Looking at a HelloWorld example in Spring MVC vs. Camel, I'm leaning towards using Spring MVC.

Camel
----
@Component
public class HelloWorldRoute extends RouteBuilder {
        @Override
        public void configure() throws Exception {
                // servlet is configured in Application.java
                restConfiguration().component("servlet").bindingMode(RestBindingMode.json);

                rest("/say")
                                .get("/hello")
                                .to("direct:talk");
                from("direct:talk")
                                .process(exchange -> {
                                        HelloWorld hw = HelloWorld.builder().message("Howdy World!").build();
                                        exchange.getIn().setBody(hw);
                                });
        }
}


Spring MVC
----
@RestController
@Api("Hello")
public class HelloWorldController {

        @RequestMapping(value = "/api/hello", method = RequestMethod.GET)
        public HelloWorld sayHello() {
                return HelloWorld.builder().message("Hello World").build();
        }
}


I was able to get Swagger working for both services, albeit with different endpoints. One issue I found is that the "base.path" has to be configured or calling the methods by clicking on buttons in Swagger UI doesn't work. With Spring Boot, I'm able to configure Swagger with the following:

@Configuration
@EnableSwagger
public class SwaggerConfig implements EnvironmentAware {
        public static final String DEFAULT_INCLUDE_PATTERN = "/api/.*";

        private RelaxedPropertyResolver propertyResolver;

        @Override
        public void setEnvironment(Environment environment) {
                this.propertyResolver = new RelaxedPropertyResolver(environment, "swagger.");
        }

        /**
         * Swagger Spring MVC configuration
         */
        @Bean
        public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin(SpringSwaggerConfig springSwaggerConfig) {
                return new SwaggerSpringMvcPlugin(springSwaggerConfig)
                                .apiInfo(apiInfo())
                                .genericModelSubstitutes(ResponseEntity.class)
                                .includePatterns(DEFAULT_INCLUDE_PATTERN);
        }

        /**
         * API Info as it appears on the swagger-ui page
         */
        private ApiInfo apiInfo() {
                return new ApiInfo(
                                propertyResolver.getProperty("title"),
                                propertyResolver.getProperty("description"),
                                propertyResolver.getProperty("termsOfServiceUrl"),
                                propertyResolver.getProperty("contact"),
                                propertyResolver.getProperty("license"),
                                propertyResolver.getProperty("licenseUrl"));
        }
}

With Camel, it's a bit less code, but if I don't override the "base.path", it defaults to localhost:8080. The Spring MVC Swagger implementation figures out the correct base path on its own.

        /**
         * Swagger Camel Configuration
         */
        @Bean
        public ServletRegistrationBean swaggerServlet() {
                ServletRegistrationBean swagger = new ServletRegistrationBean(new SpringRestSwaggerApiDeclarationServlet(), "/swagger/*");
                Map<String, String> params = new HashMap<>();
                params.put("base.path", "https://localhost:8443/rest");
                params.put("api.title", propertyResolver.getProperty("title"));
                params.put("api.description", propertyResolver.getProperty("description"));
                params.put("api.termsOfServiceUrl", propertyResolver.getProperty("termsOfServiceUrl"));
                params.put("api.version", propertyResolver.getProperty("version"));
                params.put("api.license", propertyResolver.getProperty("license"));
                params.put("api.licenseUrl", propertyResolver.getProperty("licenseUrl"));
                swagger.setInitParameters(params);
                return swagger;
        }

Is it possible to improve the SpringRestSwaggerApiDeclarationServlet so it gets the path from CamelServlet and it doesn't have to be hardcoded?

Thanks,

Matt
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Camel's Swagger vs. Spring MVC Swagger

Claus Ibsen-2
Hi

On Thu, Sep 25, 2014 at 11:23 PM, Matt Raible <[hidden email]> wrote:

> Hey all,
>
> I'm starting to develop a new application and I'm researching using Camel's REST DSL vs. Spring Boot and it's REST support. The last application I wrote used Apache Camel + Spring Boot, but I only used the external properties support from Boot. For this new application, I have a skeleton of the previous project. The new project needs to do REST (XML-based). Looking at a HelloWorld example in Spring MVC vs. Camel, I'm leaning towards using Spring MVC.
>
> Camel
> ----
> @Component
> public class HelloWorldRoute extends RouteBuilder {
>         @Override
>         public void configure() throws Exception {
>                 // servlet is configured in Application.java
>                 restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
>
>                 rest("/say")
>                                 .get("/hello")
>                                 .to("direct:talk");
>                 from("direct:talk")
>                                 .process(exchange -> {
>                                         HelloWorld hw = HelloWorld.builder().message("Howdy World!").build();
>                                         exchange.getIn().setBody(hw);
>                                 });
>         }
> }
>

Now its only a hello world, but you can embed the route in the rest
dsl directly, if you want, so its shorter


                 rest("/say")
                                 .get("/hello")
                                 .route().transform(constant("Hello World"));

>
> Spring MVC
> ----
> @RestController
> @Api("Hello")
> public class HelloWorldController {
>
>         @RequestMapping(value = "/api/hello", method = RequestMethod.GET)
>         public HelloWorld sayHello() {
>                 return HelloWorld.builder().message("Hello World").build();
>         }
> }
>
>
> I was able to get Swagger working for both services, albeit with different endpoints. One issue I found is that the "base.path" has to be configured or calling the methods by clicking on buttons in Swagger UI doesn't work. With Spring Boot, I'm able to configure Swagger with the following:
>
> @Configuration
> @EnableSwagger
> public class SwaggerConfig implements EnvironmentAware {
>         public static final String DEFAULT_INCLUDE_PATTERN = "/api/.*";
>
>         private RelaxedPropertyResolver propertyResolver;
>
>         @Override
>         public void setEnvironment(Environment environment) {
>                 this.propertyResolver = new RelaxedPropertyResolver(environment, "swagger.");
>         }
>
>         /**
>          * Swagger Spring MVC configuration
>          */
>         @Bean
>         public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin(SpringSwaggerConfig springSwaggerConfig) {
>                 return new SwaggerSpringMvcPlugin(springSwaggerConfig)
>                                 .apiInfo(apiInfo())
>                                 .genericModelSubstitutes(ResponseEntity.class)
>                                 .includePatterns(DEFAULT_INCLUDE_PATTERN);
>         }
>
>         /**
>          * API Info as it appears on the swagger-ui page
>          */
>         private ApiInfo apiInfo() {
>                 return new ApiInfo(
>                                 propertyResolver.getProperty("title"),
>                                 propertyResolver.getProperty("description"),
>                                 propertyResolver.getProperty("termsOfServiceUrl"),
>                                 propertyResolver.getProperty("contact"),
>                                 propertyResolver.getProperty("license"),
>                                 propertyResolver.getProperty("licenseUrl"));
>         }
> }
>
> With Camel, it's a bit less code, but if I don't override the "base.path", it defaults to localhost:8080. The Spring MVC Swagger implementation figures out the correct base path on its own.
>
>         /**
>          * Swagger Camel Configuration
>          */
>         @Bean
>         public ServletRegistrationBean swaggerServlet() {
>                 ServletRegistrationBean swagger = new ServletRegistrationBean(new SpringRestSwaggerApiDeclarationServlet(), "/swagger/*");
>                 Map<String, String> params = new HashMap<>();
>                 params.put("base.path", "https://localhost:8443/rest");
>                 params.put("api.title", propertyResolver.getProperty("title"));
>                 params.put("api.description", propertyResolver.getProperty("description"));
>                 params.put("api.termsOfServiceUrl", propertyResolver.getProperty("termsOfServiceUrl"));
>                 params.put("api.version", propertyResolver.getProperty("version"));
>                 params.put("api.license", propertyResolver.getProperty("license"));
>                 params.put("api.licenseUrl", propertyResolver.getProperty("licenseUrl"));
>                 swagger.setInitParameters(params);
>                 return swagger;
>         }
>
> Is it possible to improve the SpringRestSwaggerApiDeclarationServlet so it gets the path from CamelServlet and it doesn't have to be hardcoded?
>

Yeah sure we can look into that, and also make the java configuration
easier so you can use a builder instead of the map etc. Feel free to
log a JIRA ticket in the issue tracker
http://camel.apache.org/support


> Thanks,
>
> Matt



--
Claus Ibsen
-----------------
Red Hat, Inc.
Email: [hidden email]
Twitter: davsclaus
Blog: http://davsclaus.com
Author of Camel in Action: http://www.manning.com/ibsen
hawtio: http://hawt.io/
fabric8: http://fabric8.io/
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Camel's Swagger vs. Spring MVC Swagger

Matt Raible
On Fri, Sep 26, 2014 at 1:48 AM, Claus Ibsen <[hidden email]> wrote:

> Hi
>
> On Thu, Sep 25, 2014 at 11:23 PM, Matt Raible <[hidden email]>
> wrote:
> > Hey all,
> >
> > I'm starting to develop a new application and I'm researching using
> Camel's REST DSL vs. Spring Boot and it's REST support. The last
> application I wrote used Apache Camel + Spring Boot, but I only used the
> external properties support from Boot. For this new application, I have a
> skeleton of the previous project. The new project needs to do REST
> (XML-based). Looking at a HelloWorld example in Spring MVC vs. Camel, I'm
> leaning towards using Spring MVC.
> >
> > Camel
> > ----
> > @Component
> > public class HelloWorldRoute extends RouteBuilder {
> >         @Override
> >         public void configure() throws Exception {
> >                 // servlet is configured in Application.java
> >
>  restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
> >
> >                 rest("/say")
> >                                 .get("/hello")
> >                                 .to("direct:talk");
> >                 from("direct:talk")
> >                                 .process(exchange -> {
> >                                         HelloWorld hw =
> HelloWorld.builder().message("Howdy World!").build();
> >                                         exchange.getIn().setBody(hw);
> >                                 });
> >         }
> > }
> >
>
> Now its only a hello world, but you can embed the route in the rest
> dsl directly, if you want, so its shorter
>
>
>                  rest("/say")
>                                  .get("/hello")
>                                  .route().transform(constant("Hello
> World"));
>

Good to know. Is it possible to return an object with the REST DSL or only
constants?


>
> >
> > Spring MVC
> > ----
> > @RestController
> > @Api("Hello")
> > public class HelloWorldController {
> >
> >         @RequestMapping(value = "/api/hello", method = RequestMethod.GET)
> >         public HelloWorld sayHello() {
> >                 return HelloWorld.builder().message("Hello
> World").build();
> >         }
> > }
> >
> >
> > I was able to get Swagger working for both services, albeit with
> different endpoints. One issue I found is that the "base.path" has to be
> configured or calling the methods by clicking on buttons in Swagger UI
> doesn't work. With Spring Boot, I'm able to configure Swagger with the
> following:
> >
> > @Configuration
> > @EnableSwagger
> > public class SwaggerConfig implements EnvironmentAware {
> >         public static final String DEFAULT_INCLUDE_PATTERN = "/api/.*";
> >
> >         private RelaxedPropertyResolver propertyResolver;
> >
> >         @Override
> >         public void setEnvironment(Environment environment) {
> >                 this.propertyResolver = new
> RelaxedPropertyResolver(environment, "swagger.");
> >         }
> >
> >         /**
> >          * Swagger Spring MVC configuration
> >          */
> >         @Bean
> >         public SwaggerSpringMvcPlugin
> swaggerSpringMvcPlugin(SpringSwaggerConfig springSwaggerConfig) {
> >                 return new SwaggerSpringMvcPlugin(springSwaggerConfig)
> >                                 .apiInfo(apiInfo())
> >
>  .genericModelSubstitutes(ResponseEntity.class)
> >
>  .includePatterns(DEFAULT_INCLUDE_PATTERN);
> >         }
> >
> >         /**
> >          * API Info as it appears on the swagger-ui page
> >          */
> >         private ApiInfo apiInfo() {
> >                 return new ApiInfo(
> >                                 propertyResolver.getProperty("title"),
> >
>  propertyResolver.getProperty("description"),
> >
>  propertyResolver.getProperty("termsOfServiceUrl"),
> >                                 propertyResolver.getProperty("contact"),
> >                                 propertyResolver.getProperty("license"),
> >
>  propertyResolver.getProperty("licenseUrl"));
> >         }
> > }
> >
> > With Camel, it's a bit less code, but if I don't override the
> "base.path", it defaults to localhost:8080. The Spring MVC Swagger
> implementation figures out the correct base path on its own.
> >
> >         /**
> >          * Swagger Camel Configuration
> >          */
> >         @Bean
> >         public ServletRegistrationBean swaggerServlet() {
> >                 ServletRegistrationBean swagger = new
> ServletRegistrationBean(new SpringRestSwaggerApiDeclarationServlet(),
> "/swagger/*");
> >                 Map<String, String> params = new HashMap<>();
> >                 params.put("base.path", "https://localhost:8443/rest");
> >                 params.put("api.title",
> propertyResolver.getProperty("title"));
> >                 params.put("api.description",
> propertyResolver.getProperty("description"));
> >                 params.put("api.termsOfServiceUrl",
> propertyResolver.getProperty("termsOfServiceUrl"));
> >                 params.put("api.version",
> propertyResolver.getProperty("version"));
> >                 params.put("api.license",
> propertyResolver.getProperty("license"));
> >                 params.put("api.licenseUrl",
> propertyResolver.getProperty("licenseUrl"));
> >                 swagger.setInitParameters(params);
> >                 return swagger;
> >         }
> >
> > Is it possible to improve the SpringRestSwaggerApiDeclarationServlet so
> it gets the path from CamelServlet and it doesn't have to be hardcoded?
> >
>
> Yeah sure we can look into that, and also make the java configuration
> easier so you can use a builder instead of the map etc. Feel free to
> log a JIRA ticket in the issue tracker
> http://camel.apache.org/support


Done: https://issues.apache.org/jira/browse/CAMEL-7878
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: Camel's Swagger vs. Spring MVC Swagger

Claus Ibsen-2
On Sun, Sep 28, 2014 at 6:40 PM, Matt Raible <[hidden email]> wrote:

> On Fri, Sep 26, 2014 at 1:48 AM, Claus Ibsen <[hidden email]> wrote:
>
>> Hi
>>
>> On Thu, Sep 25, 2014 at 11:23 PM, Matt Raible <[hidden email]>
>> wrote:
>> > Hey all,
>> >
>> > I'm starting to develop a new application and I'm researching using
>> Camel's REST DSL vs. Spring Boot and it's REST support. The last
>> application I wrote used Apache Camel + Spring Boot, but I only used the
>> external properties support from Boot. For this new application, I have a
>> skeleton of the previous project. The new project needs to do REST
>> (XML-based). Looking at a HelloWorld example in Spring MVC vs. Camel, I'm
>> leaning towards using Spring MVC.
>> >
>> > Camel
>> > ----
>> > @Component
>> > public class HelloWorldRoute extends RouteBuilder {
>> >         @Override
>> >         public void configure() throws Exception {
>> >                 // servlet is configured in Application.java
>> >
>>  restConfiguration().component("servlet").bindingMode(RestBindingMode.json);
>> >
>> >                 rest("/say")
>> >                                 .get("/hello")
>> >                                 .to("direct:talk");
>> >                 from("direct:talk")
>> >                                 .process(exchange -> {
>> >                                         HelloWorld hw =
>> HelloWorld.builder().message("Howdy World!").build();
>> >                                         exchange.getIn().setBody(hw);
>> >                                 });
>> >         }
>> > }
>> >
>>
>> Now its only a hello world, but you can embed the route in the rest
>> dsl directly, if you want, so its shorter
>>
>>
>>                  rest("/say")
>>                                  .get("/hello")
>>                                  .route().transform(constant("Hello
>> World"));
>>
>
> Good to know. Is it possible to return an object with the REST DSL or only
> constants?
>

Yeah you can return anything you want. A constant refers to a java
instance, so it can be anything really, in the example above its a
String, eg "xxx".

If the rest component of choice support the type, then you can just
use that, eg a JAX-RS Response instance etc.

As when you use .route() you can do all the Camel routing you want,
you can also call java beans, content based routing, recipient list,
or whatever.



>
>>
>> >
>> > Spring MVC
>> > ----
>> > @RestController
>> > @Api("Hello")
>> > public class HelloWorldController {
>> >
>> >         @RequestMapping(value = "/api/hello", method = RequestMethod.GET)
>> >         public HelloWorld sayHello() {
>> >                 return HelloWorld.builder().message("Hello
>> World").build();
>> >         }
>> > }
>> >
>> >
>> > I was able to get Swagger working for both services, albeit with
>> different endpoints. One issue I found is that the "base.path" has to be
>> configured or calling the methods by clicking on buttons in Swagger UI
>> doesn't work. With Spring Boot, I'm able to configure Swagger with the
>> following:
>> >
>> > @Configuration
>> > @EnableSwagger
>> > public class SwaggerConfig implements EnvironmentAware {
>> >         public static final String DEFAULT_INCLUDE_PATTERN = "/api/.*";
>> >
>> >         private RelaxedPropertyResolver propertyResolver;
>> >
>> >         @Override
>> >         public void setEnvironment(Environment environment) {
>> >                 this.propertyResolver = new
>> RelaxedPropertyResolver(environment, "swagger.");
>> >         }
>> >
>> >         /**
>> >          * Swagger Spring MVC configuration
>> >          */
>> >         @Bean
>> >         public SwaggerSpringMvcPlugin
>> swaggerSpringMvcPlugin(SpringSwaggerConfig springSwaggerConfig) {
>> >                 return new SwaggerSpringMvcPlugin(springSwaggerConfig)
>> >                                 .apiInfo(apiInfo())
>> >
>>  .genericModelSubstitutes(ResponseEntity.class)
>> >
>>  .includePatterns(DEFAULT_INCLUDE_PATTERN);
>> >         }
>> >
>> >         /**
>> >          * API Info as it appears on the swagger-ui page
>> >          */
>> >         private ApiInfo apiInfo() {
>> >                 return new ApiInfo(
>> >                                 propertyResolver.getProperty("title"),
>> >
>>  propertyResolver.getProperty("description"),
>> >
>>  propertyResolver.getProperty("termsOfServiceUrl"),
>> >                                 propertyResolver.getProperty("contact"),
>> >                                 propertyResolver.getProperty("license"),
>> >
>>  propertyResolver.getProperty("licenseUrl"));
>> >         }
>> > }
>> >
>> > With Camel, it's a bit less code, but if I don't override the
>> "base.path", it defaults to localhost:8080. The Spring MVC Swagger
>> implementation figures out the correct base path on its own.
>> >
>> >         /**
>> >          * Swagger Camel Configuration
>> >          */
>> >         @Bean
>> >         public ServletRegistrationBean swaggerServlet() {
>> >                 ServletRegistrationBean swagger = new
>> ServletRegistrationBean(new SpringRestSwaggerApiDeclarationServlet(),
>> "/swagger/*");
>> >                 Map<String, String> params = new HashMap<>();
>> >                 params.put("base.path", "https://localhost:8443/rest");
>> >                 params.put("api.title",
>> propertyResolver.getProperty("title"));
>> >                 params.put("api.description",
>> propertyResolver.getProperty("description"));
>> >                 params.put("api.termsOfServiceUrl",
>> propertyResolver.getProperty("termsOfServiceUrl"));
>> >                 params.put("api.version",
>> propertyResolver.getProperty("version"));
>> >                 params.put("api.license",
>> propertyResolver.getProperty("license"));
>> >                 params.put("api.licenseUrl",
>> propertyResolver.getProperty("licenseUrl"));
>> >                 swagger.setInitParameters(params);
>> >                 return swagger;
>> >         }
>> >
>> > Is it possible to improve the SpringRestSwaggerApiDeclarationServlet so
>> it gets the path from CamelServlet and it doesn't have to be hardcoded?
>> >
>>
>> Yeah sure we can look into that, and also make the java configuration
>> easier so you can use a builder instead of the map etc. Feel free to
>> log a JIRA ticket in the issue tracker
>> http://camel.apache.org/support
>
>
> Done: https://issues.apache.org/jira/browse/CAMEL-7878



--
Claus Ibsen
-----------------
Red Hat, Inc.
Email: [hidden email]
Twitter: davsclaus
Blog: http://davsclaus.com
Author of Camel in Action: http://www.manning.com/ibsen
hawtio: http://hawt.io/
fabric8: http://fabric8.io/
Loading...