I am testing on an app that is making calls to a public backend.
I want to use wiremock to mock reponses from the public backends.
I was looking at something like
the app makes a request to api.example.com which is forced through the wiremock proxy on localhost:<port>
wiremock matches the URL based on the rules I provide and returns a mock response
The only examples I could find map localhost requests to real backends or mock responses to localhost.
If I'm understanding your question, the app behaves as follows:
App sends request to your backend
Your backend responds with a forwarding request to a public backend
App sends request to public backend
Public backend responds
As far as I'm aware WireMock can only achieve this if you mock out the response from your backend, and have that response's forwarding request point to another mocked out response. WireMock only knows to redirect and proxy when requests are made to WireMock. WireMock does not behave as a man-in-the-middle proxy, listening to all requests made (regardless of url) and selectively returning mocked responses. WireMock only knows to proxy/forward/respond when you hit WireMock directly. So you'd need to have something like...
{
"request" : {
"url" : "/my-backend",
"method": GET
},
"response" : {
"status" : 302,
"headers" : {
"location" : "/public-backend"
}
}
}
Which would return a forwarding request to the /public-backend url. (Depending on what your actual API looks like when it returns that forwarding request, the above response may not be accurate.) And then you'd need to mock out what that request/response mapping looks like
{
"request" : {
"url" : "/public-backend",
"method" : "GET"
},
"response" : {
// response
}
}
Depending on what you are using to run your tests, it is probably better to utilize an existing intercept/proxy functionality that the runner has to listen for requests to certain urls and return a mocked response that way. For example, TestCafe can intercept HTTP requests and return your custom responses. If you went about testing this way, then you'd be able to only have to mock out the response from the public API, and not from your backend as well.
Related
I have been trying to intercept a server request using Cypress' intercept method.
I have noticed that Cypress can intercept requests made through the front-end/browser, however, the intercept method doesn't work if I make a request directly to the back-end server.
Let me clarify what I mean:
One thing is intercepting a request that the front-end/browser makes to the back-end server.
Another thing is intercepting a call that doesn't use the browser but calls directly the back-end endpoint.
For example:
I can create a user using the front-end interface
or I can create a user calling the back-end endpoint directly (directly calling the server).
Coming back to my question. Is there a way to intercept a call that was made directly to the back-end endpoint?
This is what I have tried so far:
I wrote a regex to intercept api/v0/customers
I then made a request to http://locahost:5440/api/v0/customers (which is the URL of the server)
Finally, I waited for the request to happen
Timeout request using Cypress intercept method
cy.intercept(/^\/api\/v0\/customers\/$/).as('createCustomer');
cy.request(createCustomer(customerData, headers));
cy.wait('#createCustomer').then(({ status, body }) => {
const customerId = body.customer_id;
console.log(body);
expect(status).equal(201);
});
Here's the problem: There was a timeout error.
As you can see in the image, I'm making a request to http://locahost:5440 which is the server URL. NOTE: I made sure the server was up and running.
The regex is also correct and it will match the endpoint http://locahost:5440/api/v0/customers
I suspect that intercept only works for requests being made through the browser. Is this assertion correct? I couldn't find this answer anywhere in the Cypress docs.
Is there a way for me to intercept a call being made directly to a server (not using the browser)?
You don't have to intercept the requests you explicitly make with cypress, just use .then to get the response, like this:
cy.request(createCustomer(customerData, headers)).then((response) => {
const customerId = response.body.customer_id;
console.log(response.body);
expect(response.status).equal(201);
});
Reference: https://docs.cypress.io/api/commands/request#Yields
I would like to put Netflix Zuul 2 (https://github.com/Netflix/zuul) in front of my services and do some authentication/validation of the incoming requests.
Each request that goes through the API gateway, e.g. /api/service1/value would have an auth token and I would like to validate that token before routing the request to the appropriate backend service.
I have several questions and was hoping someone could point me in the right direction.
An inbound filter seems like the right place to put that logic.
At the moment, my understanding is that it could be done like this:
class RequestAuthenticationFilter extends HttpInboundSyncFilter {
#Override
HttpRequestMessage apply(HttpRequestMessage request) {
// extract header with token and call auth service to validate it
if (ifTokenNotValid) {
// returns a 401
request.getContext()
.setEndpoint(UnauthorizedRequestEndpoint.class.getCanonicalName())
}
// continue filter chain
return request
}
}
What I'm not sure about is how to make that call to the auth service and get the response in the inbound filter so that the response can be checked and appropriate action can be taken - either return a 401 or continue routing the /api/service1/value request to a downstream backend service.
Is there a standard approach for making that external call from the inbound filter to a service?
Would I need to import another library with a HttpClient, etc. to achieve this?
Is there a different/better approach to handle this flow?
I understand that for normal routing from an inbound filter to an endpoint a ProxyEndpoint can be used:
inbound filter config:
...
if (path in request matches) {
context.setEndpoint(ZuulEndPointRunner.PROXY_ENDPOINT_FILTER_NAME)
context.setRouteVIP("service1")
}
return request
Either Eureka config:
service1.ribbon.NIWSServerListClassName=com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
service1.ribbon.DeploymentContextBasedVipAddresses=authservice
or a list of servers configured manually:
service1.ribbon.listOfServers=localhost:8080
service1.ribbon.client.NIWSServerListClassName=com.netflix.loadbalancer.ConfigurationBasedServerList
Is there a way to configure the auth service that way and plug it into the flow, i.e.
request >> validate auth token (auth service request, response) >> continue original request?
error :"405 not allowed Method" in post method type call in request command vue
i need call api function with content-type:application/json and post Method type with request command in vue ,but browser add preflight request with options method type and it causes this error :"405 not allowed Method"
var options = {
method: "POST",
url: "http://api.sample.com/login",
headers: {
"Access-Control-Request-Method":"POST",
"cache-control": "no-cache",
"content-type": "application/json",
},
body: '{ Username: "demo", Password: "demo", Domain: "test" }'
};
request(options, function(error, response, body) {
if (error) throw new Error(error);
body.data;
alert("ok");
});
The OPTIONS call is done whenever you do a cross-origin request. This means the domain your application is running on is different from the domain where the api is. A pre-flight request is mandatory for these requests, because the browser needs to figure out if you are allowed to do these requests. A 405 error means that the server thinks you are not allowed to make that request.
To solve this problem you can move your api to the same domain as your frontend. Please note that it cannot be on a subdomain.
A different way of solving this, is by sending back the correct headers. In your case you seem to at least miss the Access-Control-Allow-Methods response header. Make sure to send this header and either dynamically figure out which methods are allowed, or do something like the following. That would allow the most common methods to work.
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
In the comments you said that you do not have control over the api, and as such cannot change the response header. In that case your best bet is to contact whoever maintains the api and ask how to best use their api.
In the comments you said that this worked fine when you did the same thing in ASP.NET. ASP.NET is a server-side language, which means that requests in that context do not have a concept of "cross-origin". Cross-origin only comes into play in the browser, where the application runs on an actual domain.
Assuming you can set up a proxy on your application domain, you can also create a proxy that proxies all requests to the api you actually want to communicate with. You would deploy your domain on https://example.com and do your requests to https://example.com/api/endpoint. Your proxy will listen for requests that begin with https://example.com/api and proxy it to https://whatever.the.api.is/ with the appropriate endpoint and data.
Please keep in mind that while some api's might just be configured incorrectly, a lack of cross-origin response headers might just mean that the api is nog meant to be consumed through the browser. Part of this could be that the request contains a secret that should not be exposed to users that use your application, but should instead only be on the server. Using a proxy in that case would set you up for impersonation attacks, because you would expose the secret to your application, but defeat the cross-origin headers by making it appear to the application that the api is on the same domain.
I am new to testing services with Angular 2 and I am trying to test a service with Http basic requests (Get and GetBYId).
- How works my service? : I have a getAllMyProducts method which consumes a REST Api exposed in a Spring boot Backend application .this web api query the products and return products for the current user.(The http request is sent with headers ).
- What I want to do? : Now I have to test this GetAll method with Jasmine and I am not sure how to do that especially regarding the current user…
My GetAllMethod in my Service:
getAll(): Observable<Product[]> {
return this.baseapiService.getAll('/product/userProducts');
}
my baseapiService that attachs header to the request:
getAll(link){
this.header = this.createHeader();
return this.http.get(this.apiurl+link, this.header)
.map(this.extractData);
}
Any examlpes or suggestions would be great. Thanks in advance
Have an ASP.NET Web API endpoint that generates JSON responses. But due to two factors can't be consumed directly from a browser.
cross-domain issues
need to provide session ticket for the API that is known only server side
So I need a lightweight server side proxy for client(browser) requests to extend the request with session key. Do not want to impose an overhead deserializing client JSON requests or Web API JSON responses in the proxy code. Would like to pass the payload "as is" and deserialize client requests only Web API side and the Web API responses only client (browser) side. That is the proxy takes json from the browser and passes it directly to Web API. It also passes the JSON response from the Web API to the browser directly without deserialization. Just a dummy proxy that does not know anything about the data it transfers.
Please suggest is it feasible and what is the best way to implement it. The existing web application (the one that is used to generate the client pages) is implemented using ASP.NET MVC 4.
Thanks in advance.
update for 2021:
You should probably be looking at https://microsoft.github.io/reverse-proxy/ if you have found your way here
old answer:
I wrote one for a previous version of WebApi. The code should be fairly easy to update for your purposes.
The basic idea is that you create a WebApi DelegatingHandler that passes the request on to an HttpClient:
public class ForwardProxyMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("X-Forwarded-For", request.GetClientIp());
if (request.Method == HttpMethod.Get || request.Method == HttpMethod.Trace) request.Content = null;
request.RequestUri = new Uri(request.RequestUri.ToString().Replace(":3002", "")); //comes through with the port for the proxy, rewrite to port 80
request.Headers.AcceptEncoding.Clear();
var responseMessage = await new HttpClient().SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
responseMessage.Headers.TransferEncodingChunked = null; //throws an error on calls to WebApi results
if (request.Method == HttpMethod.Head) responseMessage.Content = null;
return responseMessage;
}
}