Request to Cloudflare DNS from Cloudflare worker not returning the DNS result - dns

I have a Cloudflare (CF) worker that I want to have make a few DNS requests using the CF DNS (https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/).
So a pretty basic worker:
/**
* readRequestBody reads in the incoming request body
* Use await readRequestBody(..) in an async function to get the string
* #param {Request} request the incoming request to read from
*/
async function readRequestBody(request) {
const { headers } = request
const contentType = headers.get('content-type')
if (contentType.includes('application/json')) {
const body = await request.json()
return JSON.stringify(body)
}
return ''
}
/**
* Respond to the request
* #param {Request} request
*/
async function handleRequest(request) {
let reqBody = await readRequestBody(request)
var jsonTlds = JSON.parse(reqBody);
const fetchInit = {
method: 'GET',
}
let promises = []
for (const tld of jsonTlds.tlds) {
//Dummy request until I can work out why I am not getting the response of the DNS query
var requestStr = 'https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=example.com&type=A'
let promise = fetch(requestStr, fetchInit)
promises.push(promise)
}
try {
let results = await Promise.all(promises)
return new Response(JSON.stringify(results), {status: 200})
} catch(err) {
return new Response(JSON.stringify(err), {status: 500})
}
}
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request))
})
I have just hardcoded the DNS query at the moment to:
https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=example.com&type=A
and I would expect that the JSON result I would get is:
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "example.com.",
"type": 1
}
],
"Answer": [
{
"name": "example.com.",
"type": 1,
"TTL": 9540,
"data": "93.184.216.34"
}
]
}
however instead in results I get what appears to be the outcome of the websocket established as part of the fetch() (assuming I go around the loop once)
[
{
"webSocket": null,
"url": "https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=example.com&type=A",
"redirected": false,
"ok": true,
"headers": {},
"statusText": "OK",
"status": 200,
"bodyUsed": false,
"body": {
"locked": false
}
}
]
So my question is, what am I doing wrong here such that I am not getting the DNS JSON response from the 1.1.1.1 API?

fetch() returns a promise for a Response object, which contains the response status, headers, and the body stream. This object is what you're seeing in your "results". In order to read the response body, you must make further calls.
Try defining a function like this:
async function fetchJsonBody(req, init) {
let response = await fetch(req, init);
if (!response.ok()) {
// Did not return status 200; throw an error.
throw new Error(response.status + " " + response.statusText);
}
// OK, now we can read the body and parse it as JSON.
return await response.json();
}
Now you can change:
let promise = fetch(requestStr, fetchInit)
to:
let promise = fetchJsonBody(requestStr, fetchInit)

Related

axios response data to make other axios request

i want to make axios request from other axios response. and combine the console.log
i have already try
const data1 = axios.get(`https://website.com/json1respon`).then(({ data }) => {
const data2 = axios
.get(`https://website2.com/${data.data.product}`)
.then(({ data }) => {});
});
console.log(data1, data2);
json response website 1
{
"data": {
"trx_id": "T221129CEVD013700",
"ref_id": "YEPE-780HM434",
"destination": "101216575|2522",
"product": "344",
"status": "Sukses",
"sn": "мυн. яιfqу29. RefId : S221129031615475TPZI",
},
"status": 1
}
json respon website 2
{
"data": {
"res": 75000,
"pbl": 80000
}
}
so i want to combine like this
status : ${data.data.status}
serial : ${data.data.sn}
product : ${data.data.product}
price : ${data.data.pbl}
when i try it separate each other
You may use await and async features for better readability and await callback hell for the future.
try {
const data1 = await axios.get(`https://website.com/json1respon`);
const data2 = await axios.get(`https://website2.com/${data1.data.product}`);
let respt = data2.data.price;
} catch (e) {
// handle error
}

Why is displayStart (Datatable 1.10) not working for me?

I am using Datable (1.10.3) and whatever value I set in the diplayStart field, the start parameter of the server request always goes as 0.
Here is my code:
this.table = $('#table').DataTable({
displayStart: 100,
order: [[0, 'desc']],
processing: true,
serverSide: true,
searching: true,
pageLength: 50,
searchDelay: 1000,
language: {
lengthMenu: 'Show _MENU_ records per page'
},
dom: '<"top"il>rt<"bottom"p><"clear">',
ajax: {
url: <url>,
type: 'POST',
headers: {
authorization: <token>
},
data: function (d) {
//setting request data
},
dataSrc: (json) =>{
return json.data;
},
error: function (xhr, error, thrown) {
if (xhr.status + '' === '401') {
location.href = '/';
}
}
},
columns: this.getColumns(),
drawCallback: function () {
//some operations
}
});
It seems to work fine if I initialise the table like the older version, like this:
this.table = $('#table').dataTable({...
But this initialisation breaks other preexisting function calls (like search and row) in the code.
Can anyone suggest where I am going wrong and how can I fix this?
I am not sure if displayStart works with server side.
I realize this is not an ideal solution if you dont find any other you can override the pipeline method forcing it to use whatever you want:
$.fn.dataTable.pipeline = function ( opts ) {
return function ( request, drawCallback, settings ) {
request.start = 20;
return $.ajax( {
"type": opts.method,
"url": opts.url,
"data": request,
"dataType": "json",
"success": drawCallback
} );
}
};
Taken the example from: https://datatables.net/examples/server_side/pipeline.html

Elasticsearch node js point in time search_phase_execution_exception

const body = {
query: {
geo_shape: {
geometry: {
relation: 'within',
shape: {
type: 'polygon',
coordinates: [$polygon],
},
},
},
},
pit: {
id: "t_yxAwEPZXNyaS1wYzYtMjAxN3IxFjZxU2RBTzNyUXhTUV9XbzhHSk9IZ3cAFjhlclRmRGFLUU5TVHZKNXZReUc3SWcAAAAAAAALmpMWQkNwYmVSeGVRaHU2aDFZZExFRjZXZwEWNnFTZEFPM3JReFNRX1dvOEdKT0hndwAA",
keep_alive: "1m",
},
};
Query fails with search_phase_execution_exception at onBody
Without pit query works fine but it's needed to retrieve more than 10000 hits
Well, using PIT in NodeJS ElasticSearch's client is not clear, or at least is not well documented. You can create a PIT using the client like:
const pitRes = await elastic.openPointInTime({
index: index,
keep_alive: "1m"
});
pit_id = pitRes.body.id;
But there is no way to use that pit_id in the search method, and it's not documented properly :S
BUT, you can use the scroll API as follows:
const scrollSearch = await elastic.helpers.scrollSearch({
index: index,
body: {
"size": 10000,
"query": {
"query_string": {
"fields": [ "vm_ref", "org", "vm" ],
"query": organization + moreQuery
},
"sort": [
{ "utc_date": "desc" }
]
}
}});
And then read the results as follows:
let res = [];
try {
for await (const result of scrollSearch) {
res.push(...result.body.hits.hits);
}
} catch (e) {
console.log(e);
}
I know that's not the exact answer to your question, but I hope it helps ;)
The usage of point-in-time for pagination of search results is now documented in ElasticSearch. You can find more or less detailed explanations here: Paginate search results
I prepared an example that may give an idea about how to implement the workflow, described in the documentation:
async function searchWithPointInTime(cluster, index, chunkSize, keepAlive) {
if (!chunkSize) {
chunkSize = 5000;
}
if (!keepAlive) {
keepAlive = "1m";
}
const client = new Client({ node: cluster });
let pointInTimeId = null;
let searchAfter = null;
try {
// Open point in time
pointInTimeId = (await client.openPointInTime({ index, keep_alive: keepAlive })).body.id;
// Query next chunk of data
while (true) {
const size = remained === null ? chunkSize : Math.min(remained, chunkSize);
const response = await client.search({
// Pay attention: no index here (because it will come from the point-in-time)
body: {
size: chunkSize,
track_total_hits: false, // This will make query faster
query: {
// (1) TODO: put any filter you need here (instead of match_all)
match_all: {},
},
pit: {
id: pointInTimeId,
keep_alive: keepAlive,
},
// Sorting should be by _shard_doc or at least include _shard_doc
sort: [{ _shard_doc: "desc" }],
// The next parameter is very important - it tells Elastic to bring us next portion
...(searchAfter !== null && { search_after: [searchAfter] }),
},
});
const { hits } = response.body.hits;
if (!hits || !hits.length) {
break; // No more data
}
for (hit of hits) {
// (2) TODO: Do whatever you need with results
}
// Check if we done reading the data
if (hits.length < size) {
break; // We finished reading all data
}
// Get next value for the 'search after' position
// by extracting the _shard_doc from the sort key of the last hit
searchAfter = hits[hits.length - 1].sort[0];
}
} catch (ex) {
console.error(ex);
} finally {
// Close point in time
if (pointInTime) {
await client.closePointInTime({ body: { id: pointInTime } });
}
}
}

Error when trying to purchase multiple items with one transaction

I have gotten the PayPal API to work with one item and I'm now trying to get it to work with a whole "shopping-cart". I have encountered an error that I don't know how to solve. I suspect it might have to do something with the payment-jsons total value that represents the total cost of the whole transaction. However I don't know what to do about it.
Here is the error:
Error: Response Status : 400
at IncomingMessage.<anonymous> (E:\Users\willi\Documents\Node\Store\node_modules\paypal-rest-sdk\lib\client.js:130:23)
at IncomingMessage.emit (events.js:327:22)
at endReadableNT (internal/streams/readable.js:1327:12)
at processTicksAndRejections (internal/process/task_queues.js:80:21) {
response: {
name: 'MALFORMED_REQUEST',
message: 'Incoming JSON request does not map to API request',
information_link: 'https://developer.paypal.com/webapps/developer/docs/api/#MALFORMED_REQUEST',
debug_id: '9e8898a463ee3',
httpStatusCode: 400
},
httpStatusCode: 400
}
And here is the code in question
const pay = (req, res) => {
async function f() {
items = [];
req_items = req.body.body
let itemsProcessed = 0
req_items.forEach(item => {
console.log(item.id)
const param = item.id
Item.find({ _id: param })
.then((result) => {
const item_body = {
"name": result[0].title,
"sku": "001",
"price": parseFloat(result[0].price),
"currency": "EUR",
"quantity": item.amount
}
items.push(item_body)
itemsProcessed = itemsProcessed + 1
})
.catch((err) => {
console.log(err)
})
})
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve("done!"), 1000)
});
let result = await promise; // wait until the promise resolves (*)
console.log(items)
const create_payment_json = {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": "http://localhost:3000/success",
"cancel_url": "http://localhost:3000/cancel"
},
"transactions": [{
"item_list": {
"items": [items]
},
"amount": {
"currency": "EUR",
"total": parseFloat(req.body.subtotal) // 25
},
"description": "Purcahsed from the Store"
}]
};
// console.log(req.body)
// console.log(create_payment_json.transactions[0])
paypal.payment.create(create_payment_json, function (error, payment) {
if (error) {
throw error;
} else {
for(let i = 0;i < payment.links.length;i++){
if(payment.links[i].rel === 'approval_url'){
res.redirect(payment.links[i].href);
}
}
}
});
}
f();
}
API deprecation notice
You are integrating the deprecated v1/payments PayPal API. You shouldn't be doing so for a new integration; the current API is v2/checkout/orders, documented here.
Typically you'll want to create two routes on your own server, 'Create Order' and 'Capture Order', which return their own JSON when called. Then you can pair those two routes with the following approval flow: https://developer.paypal.com/demo/checkout/#/pattern/server
But as for your problem, debugging an issue like this is much simpler if you simply log your request JSON to see what the problem with it is.
If you do so, you will see that the "items" array you are sending has an array inside of an array of only one item (the other array). That array shouldn't be there.
This seems the culprit:
"items": [items]
Here you decided to make an array, which was useful when "items" was a single item (no array). But when items is already an array, you shouldn't be putting the array into a new array -- the resulting JSON won't map to an API request, and PayPal will return an error.
What you should do is get rid of those brackets and ensure that at this point in the code execution, "items" is already an array (if it wasn't before).

Mock multiple api call inside one function using Moxios

I am writing a test case for my service class. I want to mock multiple calls inside one function as I am making two API calls from one function. I tried following but it is not working
it('should get store info', async done => {
const store: any = DealersAPIFixture.generateStoreInfo();
moxios.wait(() => {
const request = moxios.requests.mostRecent();
request.respondWith({
status: 200,
response: store
});
const nextRequest = moxios.requests.at(1);
nextRequest.respondWith({
status: 200,
response: DealersAPIFixture.generateLocation()
});
});
const params = {
dealerId: store.dealerId,
storeId: store.storeId,
uid: 'h0pw1p20'
};
return DealerServices.retrieveStoreInfo(params).then((data: IStore) => {
const expectedOutput = DealersFixture.generateStoreInfo(data);
expect(data).toMatchObject(expectedOutput);
});
});
const nextRequest is always undefined
it throw error TypeError: Cannot read property 'respondWith' of undefined
here is my service class
static async retrieveStoreInfo(
queryParam: IStoreQueryString
): Promise<IStore> {
const res = await request(getDealerStoreParams(queryParam));
try {
const locationResponse = await graphQlRequest({
query: locationQuery,
variables: { storeId: res.data.storeId }
});
res.data['inventoryLocationCode'] =
locationResponse.data?.location?.inventoryLocationCode;
} catch (e) {
res.data['inventoryLocationCode'] = 'N/A';
}
return res.data;
}
Late for the party, but I had to resolve this same problem just today.
My (not ideal) solution is to use moxios.stubRequest for each request except for the last one. This solution is based on the fact that moxios.stubRequest pushes requests to moxios.requests, so, you'll be able to analyze all requests after responding to the last call.
The code will look something like this (considering you have 3 requests to do):
moxios.stubRequest("get-dealer-store-params", {
status: 200,
response: {
name: "Audi",
location: "Berlin",
}
});
moxios.stubRequest("graph-ql-request", {
status: 204,
});
moxios.wait(() => {
const lastRequest = moxios.requests.mostRecent();
lastRequest.respondWith({
status: 200,
response: {
isEverythingWentFine: true,
},
});
// Here you can analyze any request you want
// Assert getDealerStoreParams's request
const dealerStoreParamsRequest = moxios.requests.first();
expect(dealerStoreParamsRequest.config.headers.Accept).toBe("application/x-www-form-urlencoded");
// Assert graphQlRequest
const graphQlRequest = moxios.requests.get("POST", "graph-ql-request");
...
// Assert last request
expect(lastRequest.config.url).toBe("status");
});

Resources