How to mock an endpoint that masked the card number in Wiremock? - wiremock

We have an endpoint that masks card numbers. I want to mock this endpoint with Wiremock. Since it will work for more than one card number, it is not possible for me to prepare a separate mock file for each card. How can I mock this endpoint using a single file? The request sent and the response returned to this request are as follows:
Request:
{
"cardNumber": "1234561234561234"
}
Response:
{
"maskedCard": "123456******1234"
}
I prepared a Wiremock file that works only for 1 card number:
{
"request": {
"method": "POST",
"url": "/maskedCard",
"bodyPatterns": [
{
"matchesJsonPath": "[?(#.cardNumber == '1234561234561234')]"
}
]
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"maskedCard": "123456******1234"
}
}
}
How can I make this work for all incoming card numbers?

If the cardNumber attached to the request does not matter, then I would just exclude the bodyPatterns for matching.
{
"request": {
"method": "POST",
"url": "/maskedCard"
}
If you then need to take whatever the cardNumber in the request body is and mask it, I'm not aware of any out of the box solution to do that for you. Instead you'll have to write a Response Transformer to change the unmasked cardNumber to the masked CardNumber. Something like...
public class MaskCardNumbers extends ResponseTransformer {
public String getName() {
return "MaskCardNumbers";
}
#Override
public Response transform(Request request, Response response, FileSource files, Parameters parameters) {
Pattern pattern = Pattern.compile("/maskedCard");
Matcher matcher = pattern.matcher(request.getUrl());
if(matcher.matches()) {
// Logic to extract cardNumber - my library of choice is JsonSimple
JSONObject responseBody = (JSONObject) parser.parse(response.getBodyAsString());
String cardNumber = responseBody.get("cardNumber").toString();
// Logic to replace cardNumber
String maskedCard = "";
for (int i = 0; i < cardNumber.length(); i++) {
if (i < 6 || i > 11) {
maskedCard += cardNumber.charAt(i);
} else {
maskedCard += "*";
}
}
// Create response JSON Object
JSONObject responseObject = new JSONObject();
responseObject.put("cardNumber", maskedCard)
// Return responseObject
return Response.Builder.like(response).but().body(responseBody.toJSONString()).build();
}
}
}
You'd then need to make sure that WireMock launches with the transformer attached. Finally, your mapping would look like:
{
"request": {
"method": "POST",
"url": "/maskedCard"
},
"response": {
"status": 200,
"headers": {
"Content-Type": "application/json"
},
"jsonBody": {
"maskedCard": "123456******1234"
}
}
}
You might need to play around with some specifics, but I think that should get the job done, or at least get you most of the way there.

Related

Not able to receive value in response in flutter to cashfree API

I'm trying to receive response order_token from test API https://sandbox.cashfree.com/pg/orders which is used to create session of a payment gateway. Here is the code.
CFEnvironment environment = CFEnvironment.SANDBOX;
Future<dynamic> createOrder() async {
var response = await http.post(
Uri.https('https://sandbox.cashfree.com/pg/orders'),
headers: {
'Content-Type': 'application/json',
'x-client-id': 'your x-client-id',
'x-client-secret': 'your x-client-secret',
'x-api-version': '2022-01-01',
'x-request-id': 'developer_name',
},
body: jsonEncode(
{
"order_id": widget.cartId,
"order_amount": widget.grandTotal,
"order_currency": "INR",
"order_note": "Additional order info",
"customer_details": {
"customer_id": widget.address.id,
"customer_name": "name",
"customer_email": widget.email,
"customer_phone": widget.address.phone,
}
},
),
);
if (response.statusCode == 200) {
if (jsonDecode(response.body)['status'] == 'OK') {
debugPrint(jsonDecode(response.body)['order_id']);
debugPrint('log');
Logger.i(response.body);
return jsonDecode(response.body)['order_id'];
}
}
return '';
}
createSession() {
createOrder().then((value) {
try {
var session = CFSessionBuilder()
.setEnvironment(environment)
.setOrderId(widget.cartId!)
.setOrderToken(value)
.build();
return session;
} on CFException catch (e) {
debugPrint(e.message);
}
});
return null;
}
But the response seems to null and payment gateway doesn't open. What might be going wrong with my code? I tried printing response but there in null value there,What might be going wrong? How do I get a response? I've done this in postman I get a response.
replace header placeholders with actual values like your x-client-secret and others
Try this
var decodedResponse = jsonDecode(utf8.decode(response.bodyBytes)) as Map;
orderId = decodedResponse["order_id"] as String;
orderToken = decodedResponse["order_token"] as String;
Once the order is created and session is created, there are further steps, then only the checkout page will open. Refer this example - https://pub.dev/packages/flutter_cashfree_pg_sdk/example
Note :- Ideally, you shouldn't be creating order from app level. It should be done from your backend (Move the order creation to your backend).

Flutter & Woocommerce rest api for order notes

Hello I have been having hard time solving the following problem I would like to show only order notes from woocommmerce with the value "customer_note": true , see the Json request downward
{
"id": 281,
"author": "system",
"date_created": "2017-03-21T16:46:41",
"date_created_gmt": "2017-03-21T19:46:41",
"note": "Order ok!!!",
"customer_note": false,
}
This is how the data from order notes is held in my flutter code.
#override
Future<List<OrderNote>> getOrderNote(
{String? userId, String? orderId}) async {
try {
var response = await wcApi
.getAsync('orders/$orderId/notes?customer=$userId&per_page=20');
var list = <OrderNote>[];
if (response is Map && isNotBlank(response['message'])) {
throw Exception(response['message']);
} else {
for (var item in response) {
// if (item.type == 'customer') {
/// it is possible to update to `any` note
/// ref: https://woocommerce.github.io/woocommerce-rest-api-docs/#list-all-order-notes
list.add(OrderNote.fromJson(item));
// }
}
return list;
}
} catch (e) {
rethrow;
}
}
What about adding a condition inside the for loop to check the value of customer_note in the item to decide whether to add it to the list or not like the following:
for (var item in response) {
if (item['customer_note'])
{
// customer_note == true
list.add(OrderNote.fromJson(item));
}
}
I Also filter the order note containing a specific word with the following
if (item['note'].contains('État'))
{
list.add(OrderNote.fromJson(item));
}

KIE RuleServicesClient returns empty response

I receive successful but EMPTY result from Drools Execution Server when call from Java application using RuleServiceClient although REST call from Postman returns expected result.
My question: what is incorrect in my Java code?
Please find details below.
I created sample rule (if field Message.MyField == 1 then set this field to 400) and I was able to fire it on KIE Execution Server using Postmen:
POST Request to http://SERVER:8080/kie-server-webc/services/rest/server/containers/instances/kie-container:
{
"lookup": "defaultStatelessKieSession",
"commands": [{
"insert": {
"object": {
"Message": {
"myField": 1
}
},
"disconnected": false,
"out-identifier": "Message",
"return-object": true,
"entry-point": "DEFAULT"
}
}, {
"fire-all-rules": {
"max": -1,
"out-identifier": null
}
}]
}
Response (please note "myField": 500):
{
"type": "SUCCESS",
"msg": "Container kie-container successfully called.",
"result": {
"execution-results": {
"results": [
{
"key": "Message",
"value": {
"bnym.test1.Message": {
"myField": 500
}
}
}
],
"facts": [
{
"key": "Message",
"value": {
"org.drools.core.common.DefaultFactHandle": {
"external-form": "0:1:1208207159:1208207159:2:DEFAULT:NON_TRAIT:myProj.test1.Message"
}
}
}
]
}
}
}
My Java client code borrowed from tutorial is:
public class Message{
public Integer myField;
}
. . .
private static String URL = "http://SERVER:8080/kie-server-webc/services/rest/server";
private static final String USER = "user";
private static final String PASSWORD = "pwd";
. . .
public void transform() throws Exception {
Message m = new Message();
m.myField = 1;
KieServicesConfiguration config = KieServicesFactory.newRestConfiguration(URL, USER, PASSWORD);
config.setMarshallingFormat(MarshallingFormat.JSON);
kieServicesClient = KieServicesFactory.newKieServicesClient(config);
RuleServicesClient rulesClient = kieServicesClient.getServicesClient(RuleServicesClient.class);
KieCommands commandsFactory = KieServices.Factory.get().getCommands();
Command<?> insert = commandsFactory.newInsert(m);
Command<?> fireAllRules = commandsFactory.newFireAllRules();
Command<?> batchCommand = commandsFactory.newBatchExecution(Arrays.asList(insert, fireAllRules)); //0
ServiceResponse<String> executeResponse = rulesClient.executeCommands("kie-container", batchCommand);
if(executeResponse.getType() == ResponseType.SUCCESS) {
System.out.println("Commands executed with success! Response: ");
System.out.println(executeResponse.getResult());
}
}
Result:
Commands executed with success! Response:
{
"results" : [ ],
"facts" : [ ]
}
My question: what is incorrect in my Java code so result is empty?
Thank you
Try with the following command:
Message m = new Message();
m.myField = 1;
Command<?> insert = commandsFactory.newInsert(m, "Message",true, "DEFAULT");
This is equivalent to the json request you are using:
"insert": {
"object": {
"Message": {
"myField": 1
}
},
"out-identifier": "Message",
"return-object": true,
"entry-point": "DEFAULT"
}
I suggest turn on debug logging for the client to see the sent request and compare it to your other one to find what's not correct with it.
For whatever logging system your app is using, set this logger to DEBUG (or just set everything to DEBUG if that's better for you):
org.kie.server.client.impl.AbstractKieServicesClientImpl
If you want to keep using stateless session, then you should create a stateless session, follow the example code:
public static StatelessKieSession getStatelessKieSession() {
KieServices ks = KieServices.Factory.get();
KieContainer kContainer = ks.getKieClasspathContainer();
StatelessKieSession kSession = kContainer.newStatelessKieSession("defaultStatelessKieSession");
return kSession;
}
public void runRulesStateless(List<Object> objects) {
getStatelessKieSession().execute(objects);
}
public static void main(String[] args) {
runRulesStateless(Arrays.asList(new Object[] { new Message() }));
}
If you want a differente stateless session, you can configure in a kmodule.xml

Issue with Facebook messenger bot (welcome message and button message)

I'm facing 2 issues when developing a Facebook messenger bot, and I'm a newbie to programming.
I followed FB's tutorial to add the code - welcome message and deployed it in heroku, but my bot didn't pop up the said message.
app.post('/webhook/', function (req, res) {
let messaging_events = req.body.entry[0].messaging
for (let i = 0; i < messaging_events.length; i++) {
let event = req.body.entry[0].messaging[i]
let sender = event.sender.id
if (event.message && event.message.text) {
let text = event.message.text
if (text === 'Generic') {
sendGenericMessage(sender)
continue
}
if (text === 'button') {
sendbuttonmessage(sender)
continue
}
welcomemessage(sender)
//sendbuttonmessage(sender)
}
if (event.postback) {
let text = JSON.stringify(event.postback)
sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token)
continue
}
}
res.sendStatus(200) })
function welcomemessage (sender) { let messageData = {
"setting_type":"call_to_actions", "thread_state":"new_thread", "call_to_actions":[
{
"message":{
"text":"Welcome to My Company!"
}
} ] } request({
url: 'https://graph.facebook.com/v2.6/me/messages',
qs: {access_token:token},
method: 'POST',
json: {
recipient: {id:sender},
message: messageData,
} }, function(error, response, body) {
if (error) {
console.log('Error sending messages: ', error)
} else if (response.body.error) {
console.log('Error: ', response.body.error)
} }) }
How do I pop up another button when ppl clicked them? For example:
send function sendbuttonmessage(sender) after they click the web url of the button.
function sendbuttonmessage (sender) {
let messageData = {
"attachment": {
"type":"template",
"payload":{
"template_type":"button",
"text":"Welcome to Taikoo Place. How can we help?",
"buttons":[
{
"type":"web_url",
"url":"https://peterapparel.parseapp.com",
"title":"Show Website"
},
{
"type":"postback",
"title":"Service Lift Booking",
"payload":"what"
//"payload":"USER_DEFINED_PAYLOAD"
},
]
}
}
}
For the first question, you should set the welcome message buy a independent POST request as https://developers.facebook.com/docs/messenger-platform/send-api-reference#welcome_message_configuration shown because it uses different API and it should only be executed ONCE.
curl -X POST -H "Content-Type: application/json" -d '{
"setting_type":"call_to_actions",
"thread_state":"new_thread",
"call_to_actions":[
{
"message":{
"text":"Welcome to My Company!"
}
}
]
}' "https://graph.facebook.com/v2.6/<PAGE_ID>/thread_settings?access_token=<PAGE_ACCESS_TOKEN>"
For the second question, you cannot not detect when user clicks the web url of the button, because it will go to the link externally. However, you can set the message with the postback settings first, them you can process the postback when receiving the message, see how to handle postback here https://developers.facebook.com/docs/messenger-platform/quickstart
BTW also remember to set the messaging_postbacks under Subscription Fields.

Cleaner way use multiple options with RestBuilder while calling a service

I have the following code which, I'd like to write in a way that is easy to manage and easy to understand.
RestBuilder rest = new RestBuilder()
if (someoption()) {
rest = rest.post(someurl) {
contentType: application/json
json {
payload1: somepayload
payload2: somepayload1
}
}
}
else {
rest = rest.post(someurl) {
contentType: application/json
json {
payload4: somepayload4
}
}
}
The only thing different in the if/else is the json payload. The above just shows one if/else, however, in my actual code I have multiple.
Is there an easy way to manage this? I tried puttind conditional statements in JSON closure but it didn't work
Here's a generalized rest call method that you could use:
RestResponse rest(String method, String url, Closure jsonData = null) {
RestBuilder rest = new RestBuilder()
rest."$method"(url) {
contentType: "application/json"
if (jsonData) {
json {
jsonData.delegate = delegate
jsonData()
}
}
}
}
and you could call it with
RestResponse response
if (someoption()) {
response = rest('post', someurl) {
payload1: somepayload
payload2: somepayload1
}
}
else {
response = rest('post', someurl) {
payload4: somepayload4
}
}
or
def json
if (someoption()) {
json = {
payload1: somepayload
payload2: somepayload1
}
}
else {
json = {
payload4: somepayload4
}
}
RestResponse response = rest('post', someurl, json)