Examples to use netflix-feign outside of spring-boot - spring-mvc

I m looking for a example how to use netflix-feign from a NO-spring-boot app.
I have a existing SpringMVC (4.2) webapp. Now i build some "microservices" with Spring-boot + (eureka, feign) and i want to use those as backend serivces from the webapp.
thanks in advance

In the github repo you can see a few examples to use feign-client:
https://github.com/OpenFeign/feign
Basically, you would need to create an interface annotated with feign annotations and not with the Spring, one example would be (you can see much more in the github page):
public interface YourClient {
#RequestLine("POST /")
#Headers("Content-Type: application/json")
Response getSomething(#Param("id") String id);
}
Then to instantiate your feign client it's need to use its builder Feign. It's easy, and configurable:
YourClient yourClient = Feign.builder()
.decoder(new GsonDecoder()) // you could use Gson, Jackson,...
.target(YourClient .class, "https://your.url");
Then you can use it just invoking the method you want:
yourClient.getSomething("myId");

Related

Shopware 6 backend controller path

In Shopware 6, I want to call a backend (/admin) API controller from a backend / admin page using JavaScript. What is the correct way to use a relative path, probably with a built-in getter function?
Fetching /api/v1 only works if the shop is on /, but not when it is in a sub-folder.
fetch('/api/v1/my-plugin/my-custom-action', ...)
The best practice would be to write your own JS service that handles communication with your api endpoint.
We have an abstract ApiService class, you can inherit from. You can take a look at the CalculatePriceApiService for an example in the platform.
For you an implementation might look like this:
class MyPluginApiService extends ApiService {
constructor(httpClient, loginService, apiEndpoint = 'my-plugin') {
super(httpClient, loginService, apiEndpoint);
this.name = 'myPluginService';
}
myCustomAction() {
return this.httpClient
.get('my-custom-action', {
headers: this.getBasicHeaders()
})
.then((response) => {
return ApiService.handleResponse(response);
});
}
}
Notice that your api service is preconfigured to talk to your my-plugin endpoint, in the first line of the constructor, which means in all the following request you make you can use the relative route path.
Keep also in mind that the abstract ApiService will take care of resolving the configuratuion used for the Requests. Especially this means the ApiService will use the right BaseDomain including subfolders and it will automatically use an apiVersion that is supported by your shopware version. This means the apiVersion the ApiService uses in the route will increase every time a new api version is available, that means you need to work with wildcards in your backend route annotations for the api version.
Lastly keep in mind you need to register that service. That is documented here.
For you this might look like this:
Shopware.Application.addServiceProvider('myPluginService', container => {
const initContainer = Shopware.Application.getContainer('init');
return new MyPluginApiService(initContainer.httpClient, Shopware.Service('loginService'));
});
If you are talking about custom action that you implemented, you need to define route (use annotation) and register controller in routes.xml in your Resources\config\routes.xml.
Please follow that documentation
https://docs.shopware.com/en/shopware-platform-dev-en/how-to/api-controller

How to create a WebClient-object in a spring application with oauth2

I'm developing a spring application (client) that is secured with an OAuth2 provider. This application should do some REST calls to another spring application (resource server). For performing the REST calls, I will use spring's WebClient.
I therefore try to create a bean of type WebClient as can be found in several blogs.
#Configuration
public class AppConfig {
#Bean
public WebClient webClient(ReactiveClientRegistrationRepository clientRegistrations) {
ServerOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServerOAuth2AuthorizedClientExchangeFilterFunction(clientRegistrations,
new UnAuthenticatedServerOAuth2AuthorizedClientRepository());
oauth.setDefaultClientRegistrationId("myprovider");
return WebClient.builder().filter(oauth).build();
}
}
When starting the application, I get the following error:
The following candidates were found but could not be injected:
- Bean method 'clientRegistrationRepository' in 'ReactiveOAuth2ClientAutoConfiguration' not loaded because NoneNestedConditions 1 matched 0 did not; NestedCondition on ReactiveOAuth2ClientAutoConfiguration.NonServletApplicationCondition.ServletApplicationCondition found 'session' scope
Action:
Consider revisiting the entries above or defining a bean of type 'org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository' in your configuration.
As several websites recommend exactly this code for generating a WebClient instance when using OAuth2 authentication, I'm wondering what I'm doing wrong?
Do you have any suggestions for me?
Thanks.
I got the same issue. I changed the code as provided in the video : https://www.youtube.com/watch?v=1N-xwmoN83w&t=1569s and that worked
#Bean
public WebClient webClient(ClientRegistrationRepository clientRegistrationRepository , OAuth2AuthorizedClientRepository authorizedClientRepository) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth =
new ServletOAuth2AuthorizedClientExchangeFilterFunction (clientRegistrationRepository , authorizedClientRepository);
return WebClient.builder().apply(oauth.oauth2Configuration()).build();
}
Hope that helps.

aspnet-api-versioning - backward compatibility

I need to сlarify.
I have .net mvc app and I use Microsoft/aspnet-api-versioning (for ASP.NET Core).
And I have 2 controllers:
[ApiVersion("1.0")]
[Route("[controller]")]
public class OneController : Controller
{
[HttpGet]
public string Get()
{
return "Hello. I'm OneController";
}
}
and
[ApiVersion("1.1")]
[Route("[controller]")]
public class TwoController : Controller
{
[HttpGet]
public string Get()
{
return "Hello. I'm TwoController";
}
}
TwoController I added after release API with OneController.
And now if I try to use "http://localhost:59719/One?api-version=1.1" i see error:
The HTTP resource that matches the request URI 'http://localhost:59719/test?api-version=1.1' does not support the API version '1.1'.
Should I use different versions for different controllers or there is way to use one (latest) version for any request?
I understand I can add [ApiVersion("1.1")] to ALL controllers, but if I have 20 controllers...
Thanks for help.
You can define a default api version using the ApiVersioningOptions class and use this default version if none is specified:
`services.AddApiVersioning(o =>
{
o.AssumeDefaultVersionWhenUnspecified = true;
o.DefaultApiVersion = new ApiVersion(1 , 0);
});`
Besides, you should take a look at this excellent post on API versioning in ASP.NET from Scott Hanselman:
https://www.hanselman.com/blog/ASPNETCoreRESTfulWebAPIVersioningMadeEasy.aspx
In your example above, you have two different controllers with two different API versions. There is no direct relationship between these two. If you're trying to apply API versions in a centralized manner, you can achieve this using the Conventions API. You can even author and apply your own conventions via the IControllerConvention interface.
// same result as the attributes above
options.Conventions.Controller<OneController>().HasVersion(1,0);
options.Conventions.Controller<TwoController>().HasVersion(1,1);
// can also be achieved using only controller types
options.Conventions.Controller(typeof(OneController)).HasVersion(1,0);
options.Conventions.Controller(typeof(TwoController)).HasVersion(1,1);
// register your own convention that applies API versions to all controllers
options.Conventions.Add(new MyCustomApiVersionConvention());
You can also use an approach similar to what #arnaudauroux suggested, which would be:
services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.ApiVersionSelector = new CurrentImplementationApiVersionSelector(options);
});
Now any request without an API version will select the current (or highest) API version available. Beware that this could break clients.

spring MVC controller versioning

I have a spring boot application , which have a spring MVC controller. I am trying to version my rest api using Accept header.
The following is how my Controller looks like
RestController
#RequestMapping(value = "/private/")
public class AppleController {
private final AppleService appleService;
public AppleController(AppleService appleService) {
this.appleService = appleService;
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=1.0",
headers = "Accept=application/json; v=1.0")
public ResponseEntity getByappleId(#PathVariable("id") Long appleId) {
System.out.println("version1");
GetByappleIdResponse response = appleService.findByappleId(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#GetMapping(value = "apples/{id}", produces = "application/json; v=2.0",
headers = "Accept=application/json; v=2.0")
public ResponseEntity getByappleId2(#PathVariable("id") Long appleId) {
System.out.println("version2");
GetByappleIdResponse response = appleService.findByappleId2(appleId);
return new ResponseEntity<>(response, HttpStatus.OK);
}
Irrespective of the version that I am passing in the Accept header when calling the API always "getByappleId" method is called, hence only version 1 response is returned.
Is there anything wrong in my controller ?
There are many options to implement versioning of REST API:
suggested in the comments approach for manually routing your request;
making version as a part of your Accept header value, f.e.:
(headers = "Accept=application/vnd.name.v1+json")
(headers = "Accept=application/vnd.name.v2+json")
making version as a part of your mapping:
#GetMapping("apples/v1/{id})"
#GetMapping("apples/v2/{id})
So you need to decide which way to go. Some useful links:
Versioning a REST API
Best practices for API versioning?
As described in this answer: https://stackoverflow.com/a/34427044/258813 (and mentioned in the comments) Spring does not support routing using the headers like that.
If you want to support routing via a version header, I would recommend a custom routing condition and annotation - certainly if you are building a large API, it will result in less code and a more elegant solution.
You would define some annotation like #ApiVersion(1) that you can add to any method that is also a request mapping and then add the custom routing condition and it will behave correctly.
I have described using custom routing conditions and annotations (based on subdomains - but that could easily be switched to check headers instead) here: http://automateddeveloper.blogspot.co.uk/2014/12/spring-mvc-custom-routing-conditions.html

Accessing services directory when setting up Zend AMF in Codeigniter

I followed the instructions in this tutorial to set up Zend AMF as a way of passing data from my flash app to my PHP app:
http://codeigniter.com/forums/viewthread/180414/
So I have the directory structure and everything as described there. This is my gateway controller:
class Gateway extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('zend');
//root_folder + application + controllers + amf + services
define('SERVICES_FOLDER', APPPATH.'controllers/amf/services/');
}
public function index()
{
$server = new Zend_Amf_Server();
$server->setProduction(false);
//$server->addFunction('testservice');
$server->addDirectory(SERVICES_FOLDER);
echo $server->handle();
}
}
And the APPPATH is /application/ so the path defined by SERVIES_FOLDER is "/application/controllers/amf/services" which is where my file 'testservice.php' sits.
When I try and connect to that service in flash:
var gateway:String = "http://mysite.com/amf/gateway";
con.connect(gateway);
con.call("Testservice.getMessage", new Responder(onResult, onFault));
It calls the onFault method and displays the error:
Plugin by name 'Testservice' was not found in the registry;
Which makes me think that the addDirectory() line in Gateway.php was the problem somehow. Interestingly, I also cannot access the testservice function through a URL, ie by going to mysite.com/amf/services/testservice.
Any thoughts on what might be going on here?
Figured it out, sort of.
Instead of using the addDirectory method which I was having no luck with, I used the setClass method and created another class within the gateway.php file that has the functions, and now I can connect to those functions from flash.
I had an issue with this when using parent::__construct() in my service controllers. Once I removed that, the problem went away.

Resources