I developed a resteasy client for an external web service using RESTEasy Proxy Framework.
something like that:
public interface AnalyticsProvider {
#GET
#Path("/environments")
#Produces({ MediaType.APPLICATION_JSON})
List<String> getEnvironments();
#POST
#Path("/summary")
#Produces({ MediaType.APPLICATION_JSON})
#Consumes({ MediaType.APPLICATION_JSON})
List<CodeObjectSummary> getSummaries(CodeObjectSummaryRequest summaryRequest);
}
what are the ways to test it ? i mainly want to test serialisation and behaviour of the client code.
one option i found is using okhttp3.mockwebserver.MockWebServer to mock a web server.
any other options?
Related
I am invoking microservice api using feign like this now:
Response<List<AppResponse>> apps = appController.getApps();
And this is server side:
#RequestMapping(value = "/app")
#FeignClient(name = "soa-service")
public interface IAppController {
#GetMapping(value = "/list")
Response<List<AppResponse>> getApps();
}
Because the client side and server side registerd to eureka(the eureka could find the internal registed ip address),the invoke works fine.My question is : when the client and server not in one network(maybe the client not registed to eureka and deploy to external net). Is it possible to invoke microservice using domain url like "www.api.example.com/app/list"?
ps:I know one solution to change my invoke using okhttpclient,but the problem is: I must change all old feign invoke to new okhttp rest invoke.
#RequestMapping(value = "/app")
#FeignClient(name = "soa-service", url = "http://www.api.example.com/app/list")
public interface IAppController {
#GetMapping(value = "/list")
Response<List<AppResponse>> getApps();
}
I'm working on existing JSF application i need to implement rest service in this application so user can also consume data using rest api from existing jsf application.
I have tried
How can I integrate JSF with REST? but no response made on this question.
Calling REST service in my JSF application here requirement is opposite from my case.
How to redirect to JSF page from JAX-RS method? with this i have same issue.
I have follow this https://www.mkyong.com/webservices/jax-rs/restful-java-client-with-jersey-client/
downloaded jar of jersey-client-1.19.4.jar, added to library creating class
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/rest")
public class JSONService {
#GET
#Path("/get")
#Produces(MediaType.APPLICATION_JSON)
public void test(#Context HttpServletRequest request, #Context HttpServletResponse response)
throws IOException {
String myJsfPage = "i am here";
response.getWriter().write(myJsfPage);
}
}
but it gives me 404 page not found, please help me.
I can not access secured resource from another Origin. Searched a few days for solution and didn't find it, so I posted question here.
This is the story:
I created first Spring Boot Application that runs on default port 8080.
It depends on spring-boot-starter-data-rest and other dependencies and it has a GreetingRepository:
public interface GreetingRepository extends JpaRepository<Greeting, Long>, JpaSpecificationExecutor<Greeting> {}
globally enables CORS with RepositoryRestConfigurerAdapter:
#Configuration
public class GlobalRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
config.getCorsRegistry()
.addMapping("/**")
.allowedOrigins("*")
.allowedHeaders("*")
.allowedMethods("*");
}
}
I created second Spring Boot Application that runs on port 9000 that will access this Greetings resource.
And it works. Second application sends HTTP request with method GET to http://localhost:8080/api/greetings and it gets response with Json data, with HEADER Access-Control-Allow-Origin: *. Everything is fine.
But.
Then I wanted to secure my resource in first application. There I included spring-boot-starter-security dependency and made configuration in WebSecurityConfigurerAdapter:
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
UserDetailsService myUserDetailsService;
#Autowired
PasswordEncoder myPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService).passwordEncoder(myPasswordEncoder);
}
#Bean
public UserDetailsService createBeanUserDetailService() {
return new MyUserDetailsService();
}
#Bean
public PasswordEncoder createBeanPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
and made UserDetailsService and so on. (Important: I tested security before adding CORS, so this security configuration works and that is not a problem).
Then, after adding security in first application, second application sends same HTTP request with method GET to http://localhost:8080/api/greetings as the first time.
Now it gets an error:
Failed to load http://localhost:8080/api/greetings: Redirect from 'http://localhost:8080/api/greetings' to 'http://localhost:8080/login' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access.
I can not find solution for this problem. So CORS works for Spring Repository resources, and Spring Security works, but I can not access secured resource from another Origin because of /login page. How to solve this?
When Spring security is enabled, the security filters take precedence over CorsFilter. To make Spring Security aware of your CORS configuration call the cors() method in your HttpSecurity setup.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
This will give CorsFilter precedence over other Spring security filters. CorsFilter recognizes CORS preflight requests (HTTP OPTIONS calls) and allows it to go through without any security.
spring cloud eureka question: there are 3 microservices, 1 eureka server, 2 eureka client;
microservice A,B use annotation #EnableEurekaClient;
microservice A have a RESTful api "http://localhost:8080/hi". the api return "hello".
now, I call the api , use url "http://client/hi", but it doesn't work.
how use application name replace ip:port about spring cloud eureka?
the bootstrap.yml content:
spring:
application:
name: client
eureka:
client:
service-url:
defaultZone: http://${eureka.host:localhost}:${eureka.port:8761}/eureka/
There are many ways to do that and it depends on how you call REST API in your code.
If you are using RestTemplate to call the API, you can do that with #LoadBalanced RestTemplate
In your code that wants to invoke REST api, please define RestTemplate with #LoadBalanced like below.
#LoadBalanced
#Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
And when you call API, just use application name instead of host:port like below.
this.restTemplate.getForObject("http://client/hi", String.class)
If you are using SpringCloud Feign, you can define the interface to call your REST api like below (without URL)
#FeignClient(name="client")
public interface ProductResource {
:
}
And add annotation #EnableFeignClients in your spring boot application like below.
#SpringBootApplication
#EnableFeignClients
: // other annotations you need.
public class YourAPIInvokerApplication {
In both ways, you need to add a few dependencies.
I'm using RestTemplate, but i got Connection timed out: connect after put serviceName instead of localhost:port
#Bean
#LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
call API:
FraudCheckResponse fraudCheckResponse = customerConfig.restTemplate().getForObject(
"http://fraud/api/v1/fraud-check/{customerId}",
FraudCheckResponse.class,
customer.getId()
);
I'm currently running Dropwizard behind Apache httpd acting as a reverse proxy, configured like so:
<VirtualHost *:443>
<Location /api>
ProxyPass "http://my.app.org:8080/api"
<Location>
...
</VirtualHost>
With other Location settings serving static assets and some authentication thrown in. Now, httpd also performs SSL offloading, so my Dropwizard only receives the plain HTTP request.
In my Dropwizard API, I like to return a Location header indicating newly created resources:
#Path("/comment")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
class CommentResource() {
#PUT
fun create(#Context uri: UriInfo, entity: EventComment): Response {
val stored: EventComment = createEntity(entity)
return Response.created(uri.baseUriBuilder.path(MessageStream::class.java)
.resolveTemplate("realmish", entity.realmId)
.path(stored.id.toString()).build()).build()
}
This creates a Response with a Location header from JerseyUriBuilder:
Location http://my.app.org/api/messages/123
Which, on my SSL-only app, naturally fails to load (I'm actually surprised this didn't turn out to render as http://my.app.org:8080/api/messages/123 - probably also the reason why ProxyPassReverse didn't help).
I know I can force the scheme to be https by using baseUriBuilder.scheme("https"), but this gets repetitive and is an easy source of errors.
Thus my question: how can I either make Jersey generate correct front-end URLs or successfully make httpd rewrite those generated by Dropwizard?
For Jersey, you can use a pre-matching ContainerRequestFilter to rewrite the URI. For example
#PreMatching
public class SchemeRewriteFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext request) throws IOException {
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
request.setRequestUri(newUri);
}
}
Then just register it with Jersey (Dropwizard)
env.jersey().register(SchemeRewriteFilter.class);
EDIT
The above only works when you use uriInfo.getAbsolutePathBuilder(). If you want to use uriInfo.getBaseUriBuilder(), then you need to use the overloaded setRequestUri that accepts the base uri as the first arg.
URI newUri = request.getUriInfo().getRequestUriBuilder().scheme("https").build();
URI baseUri = request.getUriInfo().getBaseUriBuilder().scheme("https").build();
request.setRequestUri(baseUri, newUri);
If using Jetty, then you can avoid the hacks by registering the org.eclipse.jetty.server.ForwardedRequestCustomizer with your server. This will look at the X-Forwarded-* headers to build the base URI.
Sample using embedded Jetty:
Server jettyServer = new Server();
HttpConfiguration config = new HttpConfiguration();
config.addCustomizer(new ForwardedRequestCustomizer());
ServerConnector serverConnector = new ServerConnector(jettyServer,
new HttpConnectionFactory(config));
serverConnector.setPort(8080);
jettyServer.setConnectors(new Connector[] {serverConnector});
This seems to work whether or not you are behind a reverse proxy, so I don't know why it isn't just enabled by default.