Spring Contracts generated from Spring RestDocs: ignoring headers - spring-cloud-contract

TL;DR: I commented on this issue and got asked to open a new ticket, but then realized this is more of a question as Spring RestDocs provides a way to achieve what I want (ignoring unimportant headers in contracts) with operation preprocessor. So here we are, on our friendly SoF
The problem is I am trying to generate contracts starting from a RestDocs test (using RestAssured and junit5 if it matters). Test setup (in Kotlin) looks like:
private val defaultDocument = document("{method_name}", SpringCloudContractRestDocs.dslContract())
lateinit var spec: RequestSpecification
#BeforeEach
internal fun setUp(restDocumentationContextProvider: RestDocumentationContextProvider) {
RestAssured.port = port
spec = RequestSpecBuilder()
.setConfig(
RestAssuredConfig.config()
.objectMapperConfig(
ObjectMapperConfig.objectMapperConfig()
.jackson2ObjectMapperFactory { _, _ -> mapper }
)
)
.addFilter(defaultDocument)
.addFilter(ResponseLoggingFilter())
.log(LogDetail.ALL)
.build()
}
where mapper and port are injected as Spring beans.
The server generates a Date header, which is the time when the response is generated. This is done automatically by Spring WebMvc (I think) and I don't care at all for that header. However, the Date header causes stub generation to fail, as I decided to use Spring Cloud Contracts in a polyglot world approach to generate and upload stub to maven repository, because now the server generates a different date.
As I point out here, the ContractDslSnippet does not seem to provide a way to ignore unimportant headers and/or to add matchers (which would still an open question).
The (short) list of questions:
How can I filter out unimportant headers from generated contracts?
Can I add custom matchers for headers, like I can do for body?

How to remove unimportant header, using Spring RestDocs preprocessors:
private val defaultDocument = document("{method_name}", SpringCloudContractRestDocs.dslContract())
lateinit var spec: RequestSpecification
#BeforeEach
internal fun setUp(restDocumentationContextProvider: RestDocumentationContextProvider) {
RestAssured.port = port
spec = RequestSpecBuilder()
.setConfig(
RestAssuredConfig.config()
.objectMapperConfig(
ObjectMapperConfig.objectMapperConfig()
.jackson2ObjectMapperFactory { _, _ -> mapper }
)
)
.addFilter(
documentationConfiguration(restDocumentationContextProvider)
.operationPreprocessors()
.withResponseDefaults(Preprocessors.removeMatchingHeaders("Date"))
)
.addFilter(defaultDocument)
.addFilter(ResponseLoggingFilter())
.log(LogDetail.ALL)
.build()
}
The important part is adding a new filter (the first one), which takes care of configuring Spring RestDocs to remove the Date from all its snippets, including the contract ones.
How to add custom matchers, using the default SpringCloudContractRestDocs.dslContract(): I don't think it is actually possible right now, but might be wrong here (glad if somebody can chime in and correct me in case)

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

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

Inspecting Grails services in plugins through GrailsClassUtils

I am developing a Grails (v. 2.2.1) application that loads several Grails plugins. I would like to inspect such plugins at startup through some code in my Bootstrap.groovy.
For each plugin I would like to inspect the services and detect implemented interfaces so that I know, for each service, what features are available.
I’ve started with the following code that inspects only those plugins whose name match a particular pattern.:
def pluginManager = PluginManagerHolder.getPluginManager();
pluginManager.getAllPlugins().each {
if(it.name.startsWith("cn") && it.name.endsWith("Connector")) {
…
String serviceName = ….
…
Object service = ctx.getBean(serviceName);
println “Service:” + service /
Class[] ints1 = GrailsClassUtils.getAllInterfaces(service);
Class[] ints2 = GrailsClassUtils.getAllInterfacesForClass(service.getClass());
…
}
}
The println returns the service object, which seems existing in the form I was expecting.
Then I’ve tried the two lines/alternatives of code after and both fail.
The first one returns:
No signature of method: static org.codehaus.groovy.grails.commons.GrailsClassUtils.getAllInterfaces() is applicable for argument types: (…) …
The second one returns:
No signature of method: static org.codehaus.groovy.grails.commons.GrailsClassUtils.getAllInterfacesForClass() is applicable for argument types: (java.lang.Class) …
The second alternative is a little puzzling as the signature of the method is
getAllInterfacesForClass(java.lang.Class clazz)
Two questions:
Is this a viable method to find out what the services implements?
What am I missing in relation to GrailsClassUtils?

Processing SOAP messages with Akka

I'm in the process of building a small tool for my employer, and attempting to implement it using Akka 2 + Scala.
One of the systems I'm interfacing with has a a SOAP api, which has an interesting implementation:
----Request-------
Client ----Request----> Server
Client <---Req Ack----- Server
----Response------
Client <---Response---- Server
Client ----Resp Ack---->Server
Keeping track of the requests is done via a task id sent by the req-ack.
My question is to the SO community and anyone who has experience with akka are the following:
What would be an ideal way to handle http messages using akka for this particular scenario? I have seen examples with Akka-Mist, which looks like it's been discontinued in favor of play-mini, then there's akka-camel, which I can't seem to be able to find the library for as part of the akka 2.0.3 distribution, so I'm a little confused as to what approach I should take. Is there a recommended way to wrap a encapsulate a servlet's behavior inside an akka actor?
Thank you all in advance.
Your question is VERY open ended so I will make some assumptions about your requirements.
Request assumption: There are a lot of requests being generated upon some event.
Create a router having actors that wrap the async-http-client (https://github.com/sonatype/async-http-client). Once the async-http-client completes a request it would send a message having the ID contained in the Req Ack to a coordination actor. The coordination actor would aggregate the ID's.
The following is largely pseudocode but it's close enough to the real API that you should be able to figure out the missing pieces.
case class Request(url:String)
case class IDReceived(id:String)
case class RequestingActor extends Actor {
override def receive = {
case Request(url) => {
//set up the async client and run the request
//since it's async the client will not block and this actor can continue making generating more requests
}
}
}
class AsyncHttpClientResponseHandler(aggregationActor:ActorRef) extends SomeAsyncClientHandler {
//Override the necessary Handler methods.
override def onComplete = {
aggregationActor ! IDReceived(//get the id from the response)
}
}
class SomeEventHandlerClass {
val requestRouter = actorSystem.actorOf(Props[RequestingActor].withRouter(FromConfig(//maybe you've configured a round-robin router)), requestRouterName)
def onEvent(url:String) {
requestRouter ! Request(url)
}
}
case class AggregationActor extends Actor {
val idStorage = //some form of storage, maybe a Map if other information about the task ID needs to be stored as well. Map(id -> other information)
override def receive = {
case IDReceived(id) => //add the ID to idStorage
}
}
Response assumption: You need to do something with the data contained in the response and then mark the ID as complete. The HTTP frontend only needs to deal with this one set of messages.
Instead of trying to find a framework with Akka integration just use a simple HTTP frontend that will send messages into the Akka network you've created. I can't imagine any advantage gained by using play-mini and I think it would obscure some of the lines delineating work separation and control. That's not always the case but given the lack of requirements in your question I have nothing else to base my opinion on.
case class ResponseHandlingActor extends Actor {
val aggregationActor = actorSystem.actorFor(//the name of the aggregation router within the Actor System)
override def receive = {
case Response(data) => {
//do something with the data. If the data manipulation is blocking or long running it may warrant its own network of actors.
aggregationActor ! ResponseReceived(//get the id from the response)
}
}
}
class ScalatraFrontEnd() extends ScalatraServlet {
val responseRouter = actorSystem.actorOf(Props[RequestingActor].withRouter(FromConfig(//maybe you've configured a round-robin router)), requestRouterName)
post("/response") {
responseRouter ! Response(//data from the response)
}
}
Creating a system similar to this gives you nice separation of concerns, makes it really easy to reason about where processing takes place and plenty of room for scaling the system or extending it.

WCF Client Proxies, Client/Channel Caching in ASP.Net - Code Review

long time ASP.Net interface developer being asked to learn WCF, looking for some education on more architecture related fronts - as its not my strong suit but I'm having to deal.
In our current ASMX world we adopted a model of creating ServiceManager static classes for our interaction with web services. We're starting to migrate to WCF, attempting to follow the same model. At first I was dealing with performance problems, but I've tweaked a bit and we're running smoothly now, but I'm questioning my tactics. Here's a simplified version (removed error handling, caching, object manipulation, etc.) of what we're doing:
public static class ContentManager
{
private static StoryManagerClient _clientProxy = null;
const string _contentServiceResourceCode = "StorySvc";
// FOR CACHING
const int _getStoriesTTL = 300;
private static Dictionary<string, GetStoriesCacheItem> _getStoriesCache = new Dictionary<string, GetStoriesCacheItem>();
private static ReaderWriterLockSlim _cacheLockStories = new ReaderWriterLockSlim();
public static Story[] GetStories(string categoryGuid)
{
// OMITTED - if category is cached and not expired, return from cache
// get endpoint address from FinderClient (ResourceManagement SVC)
UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);
// Get proxy
StoryManagerClient svc = GetStoryServiceClient(ur.Url);
// create request params
GetStoriesRequest request = new GetStoriesRequest{}; // SIMPLIFIED
Manifest manifest = new Manifest{}; // SIMPLIFIED
// execute GetStories at WCF service
try
{
GetStoriesResponse response = svc.GetStories(manifest, request);
}
catch (Exception)
{
if (svc.State == CommunicationState.Faulted)
{
svc.Abort();
}
throw;
}
// OMITTED - do stuff with response, cache if needed
// return....
}
internal static StoryManagerClient GetStoryServiceClient(string endpointAddress)
{
if (_clientProxy == null)
_clientProxy = new StoryManagerClient(GetServiceBinding(_contentServiceResourceCode), new EndpointAddress(endpointAddress));
return _clientProxy;
}
public static Binding GetServiceBinding(string bindingSettingName)
{
// uses Finder service to load a binding object - our alternative to definition in web.config
}
public static void PreloadContentServiceClient()
{
// get finder location
UrlResource ur = FinderClient.GetUrlResource(_contentServiceResourceCode);
// preload proxy
GetStoryServiceClient(ur.Url);
}
}
We're running smoothly now with round-trip calls completing in the 100ms range. Creating the PreloadContentServiceClient() method and adding to our global.asax got that "first call" performance down to that same level. And you might want to know we're using the DataContractSerializer, and the "Add Service Reference" method.
I've done a lot of reading on static classes, singletons, shared data contract assemblies, how to use the ChannelFactory pattern and a whole bunch of other things that I could do to our usage model...admittedly, some of its gone over my head. And, like I said, we seem to be running smoothly. I know I'm not seeing the big picture, though. Can someone tell me what I've ended up here with regards to channel pooling, proxy failures, etc. and why I should head down the ChannelFactory path? My gut says to just do it, but my head can't comprehend why...
Thanks!
ChannelFactory is typically used when you aren't using Add Service Reference - you have the contract via a shared assembly not generated via a WSDL. Add Service Reference uses ClientBase which is essentially creating the WCF channel for you behind the scenes.
When you are dealing with REST-ful services, WebChannelFactory provides a service-client like interface based off the shared assembly contract. You can't use Add Service Reference if your service only supports a REST-ful endpoint binding.
The only difference to you is preference - do you need full access the channel for custom behaviors, bindings, etc. or does Add Service Reference + SOAP supply you with enough of an interface for your needs.

Resources