How to stub some requests and call real service for others using stubby4j - rest

I am using stubby4j to stub some service endpoints. I am currently stubbing the ones that are very heavy and not so complex to mock but I would like to call the real service for the rest of the endpoints.
Something like this:
/heavy-call-1 => stub service
/heavy-call-2 => stub service
/lightweight-call-1 => real service
/lightweight-call-2 => real service
Is there a way I can achieve this with this tool or should I consider using a different one?

You can actually make stubby call the real service and record the response for the first time, so the next requests will use this recorded response.
The way you can do this is by specifying an URL in the body of the stubbed response in your yaml file like this:
- request:
url: /1.1/direct_messages.json
query:
since_id: 240136858829479935
count: 1
response:
headers:
content-type: application/json
body: https://api.twitter.com/1.1/direct_messages.json?since_id=240136858829479935&count=1
You can find some more information in the stubby github docs: https://stubby4j.com/#key-features and https://stubby4j.com/docs/http_endpoint_configuration_howto.html#record-and-replay
Hope this helps!

Are you using webpack? If so, you can match different domains. For example:
const config = merge(common, {
devtool: 'inline-source-map',
mode: 'development',
devServer: {
historyApiFallback: true,
port: 3000,
hot: true,
proxy: [
{ path: '/heavy-all-1 ', target: 'http://localhost:8882' }, //stubby
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('development'),
}),
],
});
And the URLs that don't have the prefix described won't be stubbed.

Related

Next Js and axios instance with base url not working

I have created an axios instance like so for making api request to external server. My project contains a rest api server built with express js, frontend with next js. In dev it all works fine but after publishing to vercel all call to rest server looks like this
https://sandbox.{domain}.com/api.sandbox..com
but it should be
https://api.sandbox.{domain}.com
axios config
const instance = axios.create({
baseURL: `${API_ROOT}/v1`,
withCredentials: true,
});
my next.config.js looks like this
const nextConfig = {
reactStrictMode: false,
swcMinify: true,
images: {
domains: [
"images.unsplash.com",
"images.pexels.com",
],
},
};
I don't really where to look
I tried putting the domain directly as axios baseUrl but did not work.

Chrome DevTools protocol: how to configure a RequestPattern to capture all requests except those sent from the service server

I need to handle all request except those sent from the service server.
At present, I do it using such a way: capture all requests and into handler filter service requests.
await client.Fetch.enable({
patterns: [
{ requestStage: 'Request' },
{ requestStage: 'Response' }
], // handle all requests and responses.
});
client.Fetch.on('requestPaused', async (event: RequestPausedEvent) => {
if (isServiceRoute(event.request.url))
await continueRequestOrResponse(client, event);
...
// Handle the necessary events
});
Question: Can I do this at client.Fetch.enable() stage? E.g setup the the patterns filter so, it passes all requests (*) and rejects the service routes (started from https://service-domain-1.company.com and https://service-domain-2.company.com).

Adding CORS support to AWS API Gateway endpoints

Reading the documentation: https://docs.aws.amazon.com/cdk/api/v1/docs/aws-apigateway-readme.html
It's not clear to me that specifying CORS on an endpoint means that it only applies to that level, or all the sub-resources as well?
F.e.,
let's say I add a method at resource path - /products and
declare const productsResource: apigateway.Resource;
productsResource.addCorsPreflight({
allowOrigins: [ 'https://amazon.com' ],
allowMethods: [ 'GET', 'PUT' ]
Does that apply to /products/{productdId} as well?
});
Or do I need a separate addCorsPreflight() call for that sub-resource?
It depends on how that sub resource is defined.
If it is an actual Resource, i believe the answer is yes - you do need to define it for all other defined resources. Doing this for any given resource that is NOT a proxy connection will enable the OPTIONS method on your resource.
However if its a Proxy end point (which as a product ID i would expect) linked to a lambda it has to handle the Cors Preflight response itself.
Youd have to, for instance, (NOT working code, you need to define how to know if this is a preflight or not based on the incoming event from Api Gateway that triggers the lambda)
exports.handler = async (event) => {
const response = {
statusCode: 200,
headers: {
"Access-Control-Allow-Headers" : "Content-Type",
"Access-Control-Allow-Origin": "https://www.example.com",
"Access-Control-Allow-Methods": "OPTIONS,POST,GET"
},
body: JSON.stringify('Hello from Lambda!'),
};
if preflight:
return response;
};
Find more information here: https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html

Cache-control directive (only-if-cached) changed by dev-tools?

We are working on a Progessive Web App, for which the service worker intercepts the network traffic (via the fetch event handler). We have noticed, that sometimes a certain request fails here, because Request.cache is only-if-cached and Request.mode is no-cors, but not same-origin.
So it is similar to this problem.
Then I've noticed, that this happens only when the Chrome (v 65) DevTools are not opened. Does anybody notice the same phenomenon and does anybody have an idea, why this happens this way?
Parts of the request:
bodyUsed: false,
cache: "only-if-cached",
credentials: "include",
destination: "unknown",
headers: Headers {},
integrity: "",
method: "GET",
mode: "no-cors",
redirect: "follow",
referrer: "",
referrerPolicy: "no-referrer-when-downgrade",
url: "https://example.com/path/to/app-name/#!
We are handling this problem like this, but I'm afraid, that this is not appropriate.
serviceWorkerGlobal.addEventListener('fetch', function(event)
{
if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') {
var oStrangeRequest = event.request.clone();
console.log('Fetch. Request cache has only-if-cached, but not same-origin.',
oStrangeRequest.cache, oStrangeRequest.mode,
'request redirect:',
oStrangeRequest.redirect, oStrangeRequest.url, oStrangeRequest);
return;
}
// ...
});
This is a bug. You can check the progress of the fix here: https://bugs.chromium.org/p/chromium/issues/detail?id=823392

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}