Swagger not showing my controllers. Tried Postman, my endpoints still failling - java

Hope you're all doing great. I'm trying to code API's with Java and Springboot as my framework. I'm using sqlServer as my database. I did the whole configuration to make the connection possible (enabled tcp/ip protocols, got sql servers up, used an sql server jar file and dll file in my project, allowed remote connections with sql server). When i execute a query in my project in works and shows me the data in the console. BUT, when I use Swagger, there isn't my User controllers and it's methods, it just brings the basic error controller.
I have the swagger dependencies in my pom file, and I have the #EnableSwagger2 in my main application.
This is what happens when I use postman:
I don't know what to do, I can't try my API's.
Here u can see my user controller:
import JDBC.DAO.UsuarioDAO;
import JDBC.DTO.Usuario;
import org.springframework.web.bind.annotation.*;
import java.sql.SQLException;
import java.util.List;
#RestController
#RequestMapping("/")
#CrossOrigin(origins = "*", maxAge = 3600)
public class UsuarioResource {
//Get usuario por rut
#RequestMapping(method = RequestMethod.GET, value = "traerUsuario/{rut}")
public List<Usuario> obtenerUsuarioPorRut (#PathVariable ("rut") String rut) throws SQLException {
List<Usuario> user = new UsuarioDAO().obtenerUsuarioPorRut(rut);
return user;
}
//Get todos los usuarios
#RequestMapping(method = RequestMethod.GET, value = "allUsers")
public List <Usuario> getUsuarios() throws SQLException {
List <Usuario> usuarios = new UsuarioDAO().obtenerUsuarios();
return usuarios;
}
}
You can see my url should be localhost:8080/whateverendpointgoeshere (When I run my application it says running op port 8080).
This is the ConnectionManager I made to, uh, connect to the database (It works because as I said before, it brings me data when I do it directly in my IDE):
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class ConnectionManager {
private static Connection connection = null;
private static String connectionString = "jdbc:sqlserver://localhost:1433; databasename=prac; integratedSecurity=true";
public static Connection obtenerConexion() throws SQLException {
if (connection == null)
connection = DriverManager.getConnection(connectionString);
return connection;
}
}
In this image you can see why I'm using port 1433 to connect to sql server, I'm following what the TCP/IP says:
Swagger dependencies in my pom file:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
So... I've been stuck for some days trying to figure out why I can't hit my endpoints. I would appreciate some help.

I think since you can't access the endpoints even without swagger, this is an issue with your package structure. Your controller package and all other component packages (eg. service, repository) should be a subpackage under the package your main class (SpringBootApplication.java) is in. (If not a subpackage of your main class's package, you need to manually add them in #ComponentScan annotation.)

You need have configuration file for Swagger in spring boot.
#Configuration
public class SpringFoxConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
}
Annotate the class with #Configuration . You can leave the rest same as above .
Restarting the server and hitting swagger URL should fix it .

Related

Micronaut Embedded Server vs localhost

I'm getting started with micronaut and I would like to understand the difference between testing the controller using local host and using an Embedded server
For example
I have a simple controller
#Controller("/hello")
public class HelloController {
#Get("/test")
#Produces(MediaType.TEXT_PLAIN)
public String index() {
return "Hello World";
}
}
and the tested class
#MicronautTest
public class HelloControllerTest {
#Inject
#Client("/hello")
RxHttpClient helloClient;
#Test
public void testHello() {
HttpRequest<String> request = HttpRequest.GET("/test");
String body = helloClient.toBlocking().retrieve(request);
assertNotNull(body);
assertEquals("Hello World", body);
}
}
I got the logs:
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Sending HTTP Request: GET /hello/test
14:32:54.382 [nioEventLoopGroup-1-3] DEBUG mylogger - Chosen Server: localhost(51995)
But then, in which cases we need an Embedded Server? why?
where I can find documentation to understand it. I read the documentation from Micronaut but is not clear for me, what is actually occurring and why?
like this example:
#Test
public void testIndex() throws Exception {
EmbeddedServer server = ApplicationContext.run(EmbeddedServer.class);
RxHttpClient client = server.getApplicationContext().createBean(RxHttpClient.class, server.getURL());
assertEquals(HttpStatus.OK, client.toBlocking().exchange("/hello/status").status());
server.stop();
}
In both cases, you are using EmbeddedServer implementation - NettyHttpServer. This is an abstraction that represents Micronaut server implementation (a NettyHttpServer in this case).
The main difference is that micronaut-test provides components and annotations that make writing Micronaut HTTP unit tests much simpler. Before micronaut-test, you had to start up your application manually with:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
Then you had to prepare an HTTP client, for instance:
HttpClient http = HttpClient.create(server.URL)
The micronaut-test simplifies it to adding #MicronautTest annotation over the test class, and the runner starts the embedded server and initializes all beans you can inject. Just like you do with injecting RxHttpClient in your example.
The second thing worth mentioning is that the #MicronautTest annotation also allows you to use #MockBean annotation to override existing bean with some mock you can define at the test level. By default, #MicronautTest does not mock any beans, so the application that starts reflect 1:1 application's runtime environment. The same thing happens when you start EmbeddedServer manually - this is just a programmatic way of starting a regular Micronaut application.
So the conclusion is quite simple - if you want to write less boilerplate code in your test classes, use micronaut-test with all its annotations to make your tests simpler. Without it, you will have to manually control all things (starting Micronaut application, retrieving beans from application context instead of using #Inject annotation, and so on.)
Last but not least, here is the same test written without micronaut-test:
package com.github.wololock.micronaut.products
import io.micronaut.context.ApplicationContext
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.RxHttpClient
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification
class ProductControllerSpec extends Specification {
#Shared
#AutoCleanup
EmbeddedServer server = ApplicationContext.run(EmbeddedServer)
#Shared
#AutoCleanup
HttpClient http = server.applicationContext.createBean(RxHttpClient, server.URL)
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
In this case, we can't use #Inject annotation and the only way to create/inject beans is to use applicationContext object directly. (Keep in mind that in this case, RxHttpClient bean does not exist in the context and we have to create it - in micronaut-test case this bean is prepared for us upfront.)
And here is the same test that uses micronaut-test to make the test much simpler:
package com.github.wololock.micronaut.products
import io.micronaut.http.HttpRequest
import io.micronaut.http.HttpStatus
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.test.annotation.MicronautTest
import spock.lang.Specification
import javax.inject.Inject
#MicronautTest
class ProductControllerSpec extends Specification {
#Inject
#Client("/")
HttpClient http
def "should return PROD-001"() {
when:
Product product = http.toBlocking().retrieve(HttpRequest.GET("/product/PROD-001"), Product)
then:
product.id == 'PROD-001'
and:
product.name == 'Micronaut in Action'
and:
product.price == 29.99
}
def "should support 404 response"() {
when:
http.toBlocking().exchange(HttpRequest.GET("/product/PROD-009"))
then:
def e = thrown HttpClientResponseException
e.status == HttpStatus.NOT_FOUND
}
}
Less boilerplate code, and the same effect. We could even #Inject EmbeddedServer embeddedServer if would like to access it, but there is no need to do so.

Simple Spring Java #Configuration to #Autowire without #Bean

I want to make use of spring #Autowired in a java rest project. For the last days, I am trying to set up a simple spring java project with java configuration without explicit bean configuration to check that functionality out. But I can't get it to work. I may be missing something fundamental.
None of the approaches I found in the web and on this site solved my problem so far. I couldn't find a sample for exactly what I'm trying to achieve too. This is mainly due to the amount of different spring versions and approaches spread over the web.
Here is an as easy as I could come up with Java Spring rest sample. I added a few comments with how I interpret spring annotations, as I may err here too:
App base class
package restoverflow;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
#ApplicationPath("/")
public class App extends Application {
}
Config class
package restoverflow;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
#Configuration //this is a configuration class and also found by spring scan
#ComponentScan //this package and its subpackages are being checked for components and its subtypes
public class AppConfig {
}
Some Pojo
package restoverflow;
public class Pojo {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
A service
package restoverflow;
import org.springframework.stereotype.Service;
#Service //this is a subtype of component and found by the componentscan
public class PojoService {
public Pojo getPojo(){
Pojo pojo = new Pojo();
pojo.setName("pojoName");
return pojo;
}
}
And finally a resource where the autowiring of the service should be done
package restoverflow;
import javax.ws.rs.GET;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/resource")
#Controller //this is a subtype of component and found by the componentscan
public class Resource {
#Autowired //this tells to automatically instantiate PojoService with a default contructor instance of PojoService
private PojoService pojoService;
#GET
#Produces(MediaType.APPLICATION_JSON)
public Pojo getPojo() {
return pojoService.getPojo();
}
}
Pom:
...
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.1.7.RELEASE</version>
</dependency>
...
I want the pojoService to be instantiated. But I get a NullPointerException.
It looks like you are using Field level injection.
Please go through below link to understand all types of injections:
https://www.vojtechruzicka.com/field-dependency-injection-considered-harmful/
Can't see any clear reason why pojoService is coming null.
Please check whether pojoService bean is being initialized properly. It might be due to pojoService bean has not been initialized and you are getting null in your controller.
A nullpointer instead of a NoSuchBeanDefinitionException is more of an indication that the Spring context is not loaded at all, rather than loaded improperly.
If you're using Spring boot, modify your main class to initialize Spring:
#SpringBootApplication
#ApplicationPath("/")
public class App extends Application {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Or else (as the pom.xml snippet did not mention Spring boot), initialize Spring manually by initializing a ClassPathXmlApplicationContext and adding <context:component-scan base-package="restoverflow" /> in your applicationContext.xml.

Getting directed to 404 page in Spring Boot backend

I am working on Spring Boot application. I have my jsp frontend and my java backend. When I up the project in tomcat server I can see the frontend get upped. But when I try to direct the url to check the backend performance I am getting directed to 404.
Example http://localhost:8090/orders
#RequestMapping paths were defined in the correct way.I am using workbench in my case.
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/csse_ass
spring.datasource.username=root
spring.datasource.password=1234
spring.jpa.hibernate.ddl-auto=create
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
pom.xml (I have so many dependencies, I add the essential one here)
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
controller
private OrderService orderService;
#RequestMapping("/orders")
public List<Order> getAllOrders(){
return orderService.getAllOrders();
}
service
#Autowired
private OrderRepository orderRepository;
public List<Order> getAllOrders(){
List<Order> orders = new ArrayList<>();
for (Order order : orderRepository.findAll()) {
orders.add(order);
}
return orders;
}
repository
public interface OrderRepository extends CrudRepository<Order,String> {}
As well as I have my order.java class.I hope it doesn't matter in this problem.
I get no errors in my terminal except the tomcat errors which is common.
Question
Why I am getting directed to 404 page as I mentioned in the very top of the question?
Somebody fix this issue for me, cuz I couldn't figure out the problem.
try this...
#RequestMapping("/orders")
#ResponseBody
public List<Order> getAllOrders(){
return orderService.getAllOrders();
}
use #Controller annotation also..

Swagger not generating the REST documentation

I'm trying to let Swagger autogenerate che documentation of my REST APIs but I only get a partial result.
I'm using Resteasy. I added the Maven Swagger dependency
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>1.5.3</version>
</dependency>
Then I configured my Application object
package com.myapp.init;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import io.swagger.jaxrs.config.BeanConfig;
import io.swagger.jaxrs.listing.ApiListingResource;
import io.swagger.jaxrs.listing.SwaggerSerializers;
#ApplicationPath("/rest")
public class WebappInit extends Application {
public WebappInit() {
BeanConfig beanConfig = new BeanConfig();
beanConfig.setVersion("1.0.0");
beanConfig.setSchemes(new String[]{"http"});
beanConfig.setHost("theIP:8080");
beanConfig.setBasePath("/myapp/rest/");
beanConfig.setResourcePackage("the.resource.package");
beanConfig.setScan(true);
beanConfig.setPrettyPrint(true);
}
public Set<Class<?>> getClasses() {
Set<Class<?>> s = new HashSet<Class<?>>();
// here I add my REST WSs
s.add(ApiListingResource.class);
s.add(SwaggerSerializers.class);
return s;
}
}
Then I run the web application (on a Wildfly 9 server) and go to the URL http://localhost:8080/myapp/rest/swagger.json. That's what I get
{
swagger: "2.0",
info: {
version: "1.0.0"
},
host: "10.17.36.215:8080",
basePath: "/devops/rest/",
schemes: [
"http"
]
}
It seems that Swagger cannot build the REST documentation, even though my REST endpoints are reachable and are added to the Swagger list of resources.
What can be the problem?
Thank you
Giulio
Update: I checked that in the Swagger init method BeanConfig.classes() my REST classes are correctly discovered.
You need to add an #Api annotation to your resource classes.
For example:
package my.sample;
import io.swagger.annotations.Api;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.core.Response;
#Api
#Path ("/mypath")
public class MyResource
{
#GET
public Response myEndpoint()
{
return Response.ok ();
}
}
I think I got your problem. Your root service extends Application that allows dynamic building of your resources hierarchy. I believe that swagger even cannot support this technique because it generates its metadata (json files) at compile time.
I always use annotation based REST services, i.e. each resource is annotated with appropriate #Path annotation. The framework initializes all resources automatically, so I do not have to extend my root resource from Application and implement getClasses(). In this case swagger can extract all your resources and generate json files at compile time by analyzing of JAXRS annotations like #Path, #PathParam, #GET, #POST etc.
You have to add #Api annotation to your resource class and load the resource package in setResourcePackage method. It should do the magic.

How to test a Jersey REST web service?

I have written a Restful Web service and have to test it using JUnit4. I have already written a Client using Jersey Client. But want to know if I can test my service only with junit4. Can someone help me with sample at least.
My rest service has authenticate method that takes user name, password and returns a token.
I have written test case for authenticate method. But I am not sure how to test using url.
public class TestAuthenticate {
Service service = new Service();
String username = "user";
String password = "password";
String token;
#Test(expected = Exception.class)
public final void testAuthenticateInputs() {
password = "pass";
service.authenticate(username, password);
}
#Test(expected = Exception.class)
public final void testAuthenticateException(){
username = null;
String token = service.authenticate(username, password);
assertNotNull(token);
}
#Test
public final void testAuthenticateResult() {
String token = service.authenticate(username, password);
assertNotNull(token);
}
}
If you want to test using the URL, then you will need to start a server from your test. You can explicitly start an embedded server, which is pretty common for tests. Something like
public class MyResourceTest {
public static final String BASE_URI = "http://localhost:8080/api/";
private HttpServer server;
#Before
public void setUp() throws Exception {
final ResourceConfig rc = new ResourceConfig(Service.class);
server = GrizzlyHttpServerFactory.createHttpServer(URI.create(BASE_URI), rc);
}
#After
public void tearDown() throws Exception {
server.stop();
}
#Test
public void testService() {
Client client = ClientBuilder.newClient();
WebTarget target = client.target(BASE_URI).path("service");
...
}
}
It's basically an integration test. You're starting the Grizzly container and loading a ResourceConfig to the server with only the Service class. Of course you could add more classes to the configuration. You can use "real" resource config if you wanted.
The above test uses this dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
<version>${jersey2.version}</version>
</dependency>
Another option, which is the one I prefer, is to make use of the Jersey Test Framework, which will start an embedded container for you. A test might look something more like
public class SimpleTest extends JerseyTest {
#Override
protected Application configure() {
return new ResourceConfig(Service.class);
}
#Test
public void test() {
String hello = target("service").request().get(String.class);
}
}
Using this dependency
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>${jersey2.version}</version>
<scope>test</scope>
</dependency>
And embedded Grizzly container will get started under the hood, with your ResourceConfig configuration. In both examples above it is assumed the #Path value for the Service class is service, as you can see in the test URLs.
Some Resources
Jersey 2 Test Framework user guide
Some Examples
How to write Unit Test for this class using Jersey 2 test framework
How to in-memory unit test Spring-Jersey
Example with Mockito, Test Framework, and Jersey 2
Example with Mockito, Test Framework, and Jersey 1
UPDATE
If you're not using Maven, here are the jars you will need to run an embedded Grizzly container for the Jersey Test Fraemwork
I usually search for all my jars here. You can select the version and there should be a link in the next page, to download. You can use the search bar to search for the others.
Here's a simple running example, once you have all the jars
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.WebComponent;
import com.sun.jersey.test.framework.JerseyTest;
import com.sun.jersey.test.framework.WebAppDescriptor;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import junit.framework.Assert;
import org.junit.Test;
public class SimpleTest extends JerseyTest {
#Path("service")
public static class Service {
#GET
public String getTest() { return "Hello World!"; }
}
public static class AppConfig extends DefaultResourceConfig {
public AppConfig() {
super(Service.class);
}
}
#Override
public WebAppDescriptor configure() {
return new WebAppDescriptor.Builder()
.initParam(WebComponent.RESOURCE_CONFIG_CLASS,
AppConfig.class.getName())
.build();
}
#Test
public void doTest() {
WebResource resource = resource().path("service");
String result = resource.get(String.class);
Assert.assertEquals("Hello World!", result);
System.out.println(result);
}
}
You're most likely not going to have the resources and ResourceConfig in the same class as the test, but I just want to keep it simple and all visible in one class.
Whether you are using a web.xml or a ResourceConfig subclass (as shown above), you can cut down what you test by using a separate ResourceConfig, built in the test class, as I have done. Otherwise, if you are using your normal ResourceConfig class, you can just replace it in the configure method.
The configure method, is pretty much just building a web.xml file, just in Java code. You can see different methods in the WebAppDescriptor.Builder, like initParam, which is the same as an <init-param> in your web xml. You can simply use the string in the arguments, but there are some constants, as I used above.
The #Test is you usual JUnit test that will run. It is using the Jersey Client. But instead of creating the Client, you can simply just use the preconfigured Client by just accessing the resource() method, which returns a WebResource. If you are familiar with the Jersey Client, then this class should not be new to you.
Take a look at Alchemy rest client generator. This can generate a proxy implementation for your JAX-RS webservice class using jersey client behind the scene. Effectively you will call you webservice methods as simple java methods from your unit tests. Handles http authentication as well.
There is no code generation involved if you need to simply run tests so it is convenient.
The demo here setup up grizzly and uses the generator above to run junit tests.
Disclaimer: I am the author of this library.
I think #peeskillet has given you the needed prerequisites, i.e you need to run your web-service in an embedded web server. You could also look into dropwizard or spring-boot support for doing this conveniently.
As for actually verifying the response I would keep it simple and go with JUnit & http-matchers (see https://github.com/valid4j/http-matchers)

Categories