Benchmark express apis with autocannon from postman collection - node.js

I need to benchmark all my express apis.
I found this package on github. Examples are listed only for one get request.
There are also some other samples for other requests as well.
I want to know should I create a separate script for all the APIs and run them once.
I already have a postman collection for all the APIs. Is there any way I can use that to benchmark them?
If there is any other way to benchmark express APIs, please suggest.
Update
const autocannon = require("autocannon");
const fs = require("fs");
const collection = JSON.parse(fs.readFileSync("./customer-apis-v1.3.2.json", "UTF-8"));
const requests = collection.item;
(async function test() {
for (const request of requests) {
console.log(`Testing ${request.name}`);
for (const item of request.item) {
const result = await autocannon({
title: item.name,
url: item.request.url.raw,
method: item.request.method,
});
autocannon.printResult(result);
}
}
})().catch((error) => console.log(error));

You can export your Postman Collection as JSON.
Right Click on the collection
Click export
Choose Collection type
Click export
The exported file will be a .json file and will look like this:
{
"info": {
"_postman_id": "...",
"name": "...",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "name",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "http://...",
"protocol": "http",
"host": [
...
],
"path": [
...
],
"query": [
{
"key": "...",
"value": "..."
}
]
}
},
"response": []
}
],
"protocolProfileBehavior": {}
}
Then you can use autocannon programatically and read the json file
const autocannon = require("autocannon");
const fs = require("fs");
// read array of items from exported .json file from postman
const requests = JSON.parse(fs.readFileSync("path/to/postman/exported.json", "UTF-8")).items;
async function test() {
for (const item of requests) {
// test request using autocannon, pass the method, body, etc. on the autocannon options
// you might need to manipulate your data in item so you can pass it to autocannon
console.log(`Testing ${item.name}`);
const result = await autocannon({
url: item.request.url.raw,
method: item.request.method,
... // read other options here: https://github.com/mcollina/autocannon#autocannonopts-cb
})
console.log(result);
// or print table
autocannon.printResult(result);
}
}
You can also do it without await
The other way is to use Postman built-in Testing utility
Right click on the collection
Click Edit
Click Tests tab
Write your test script there
Doc about writing test: https://learning.postman.com/docs/writing-scripts/test-scripts/
Doc about monitoring test performance: https://learning.postman.com/docs/designing-and-developing-your-api/monitoring-your-api/intro-monitors/

Related

Node.JS module error - Is not a function when calling it from my index.js

I am trying to make use of a newly create Node.JS module but I am getting an error saying: "Is not a function".
lib/weather.mjs
My module's code is below:
// Gets the weather of a given location
import fetch from 'node-fetch';
var latLongAirports = [{
"name": "Madrid",
"iata": "MAD",
"lat": 40.49565434242003,
"long": -3.574541319609411,
},{
"name": "Los Angeles",
"iata": "LAX",
"lat": 33.93771087455066,
"long": -118.4007447751959,
},{
"name": "Mexico City",
"iata": "MEX",
"lat": 19.437281814699613,
"long": -99.06588831304731,}]
export default function getTemperature (iata){
async (dispatch) =>{
let data = latLongAirports.find(el => el.iata === iata);
var url = "http://www.7timer.info/bin/api.pl?lon=" + data.long + "&lat=" + data.lat + "&product=astro&output=json"
const response = await fetch(url);
const myJson = await response.json();
return myJson.dataseries[0].temp2m
}
}
And this is how I am trying to use it from my main.js
import weather from './lib/weather.mjs'
var temperature = weather.getTemperature("MEX")
What am I doing wrong here?
How should I declare and use self written modules like those?
Thank you!
weather.mjs is exporting the function. So what you get in main.js is the actual function.
In your main.js you should call the exported method like
import getTemperature from './lib/weather.mjs'
var temperature = getTemperature("MEX")

Looping through API response Node JS

I'm trying to pull data from an API and insert it into a MySQL Database. The API has over 100 objects but I can't find any information on how to do this?
I'm using node-fetch to output the Json Data but can't loop through each object? I've added a snippet of the API.
[
{
"id": 1,
"name": "Device_1"
},
{
"id": 2,
"name": "Device_2"
}
]
let responseFromApi = [
{
"id": 1,
"name": "Device_1"
},
{
"id": 2,
"name": "Device_2"
}
];
let insertMany = db.query(
'INSERT INTO your_table (id, name) VALUES ?',
[responseFromApi.map(res => [res.id, res.name])],
);
for refrence go through the documentation -->
https://www.mysqltutorial.org/mysql-nodejs/insert/
You can also use query builders such as KnexJs and others
If I understand what you mean, you can use foreach to access any of the features of the object, such as the example below.
Object.keys(obj).forEach(function(k){
console.log(k + ' - ' + obj[k].id);
});
Worked it out, should have known now that I look at it, but to help anyone in the future I'll leave the solution.
const fetch = require('node-fetch');
let settings = {
method: "Get"
};
fetch('http://127.0.0.1:3000/test', settings)
.then(res => res.json())
.then((json) => {
for (var i = 0; i < json.length; i++) {
json.id = json[i].id;
console.log(json.id);
}
});

In Azure Functions, run Cosmos DB query in code

Can I run a Cosmos DB Query in the code itself? All I could do right now is run a query before the code runs (input). What I need is to first run some code and then grab data in cosmos DB. How do I do this using javascript?
When using the Input Binding, there is an option (but only for C#) to pull in the DocumentClient, which you can use to run any query or operation.
If your constraint is running on JavaScript, you can certainly use the Cosmos DB JS SDK directly within your Function instead of using the Input Binding like so:
const cosmos = require('#azure/cosmos');
const endpoint = process.env.COSMOS_API_URL;
const masterKey = process.env.COSMOS_API_KEY;
const { CosmosClient } = cosmos;
const client = new CosmosClient({ endpoint, auth: { masterKey } });
// All function invocations also reference the same database and container.
const container = client.database("MyDatabaseName").container("MyContainerName");
module.exports = async function (context) {
const querySpec = {
query: "SELECT * FROM Families f WHERE f.lastName = #lastName",
parameters: [
{
name: "#lastName",
value: "Andersen"
}
]
};
const { result: results } = await container.items.query(querySpec).toArray();
context.log(results);
}
COSMOS_API_URL and COSMOS_API_KEY should be environment variables pointing to the Azure Cosmos account endpoint and Master Key. You can replace the names of the database and container and tinker with the query as needed.
You could refer to the example code in this link:
function.json:
{
"bindings": [
{
"name": "query",
"type": "httpTrigger",
"direction": "in"
},
{
"name": "$return",
"type": "http",
"direction": "out"
},
{
"type": "documentDB",
"name": "documents",
"databaseName": "<your-database-name>",
"collectionName": "<your-collection-name>",
"sqlQuery": "SELECT * FROM d WHERE d.name = {Name} and d.city = {City}",
"connection": "<connectionstring-setting-name>",
"direction": "in"
}
],
"disabled": false
}
function code:
module.exports = function (context, req) {
var documents = context.bindings.documents;
var totalDocuments = documents.length;
context.log('Found '+ totalDocuments +' documents');
if(totalDocuments === 0){
context.res = {
status: 404,
body : "No documents found"
};
}
else {
context.res = {
body: documents
};
}
context.done();
};
Please note: above code works for the Azure Function V1 binding configuration.

Unable to parse xml to json properly

I'm trying to parse a xml to json & i'm using xml2js in nodejs.
Below is my code
var chai = require('chai');
var chaiHttp = require('chai-http');
var request = chai.request;
var should = chai.should();
var expect = chai.expect;
var assert = chai.assert;
var supertest = require('supertest');
var fs = require('fs');
var xmlLocation = "./configdata/xmlDoc.xml";
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
//Plugin for HTTP, etc.
chai.use(chaiHttp);
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0';
//xmlFile = JSON.parse(fs.readFileSync(xmlData, 'utf8'));
describe("Test : ", function () {
it("convert xml to json", function (done) {
r = fs.readFileSync(xmlLocation, 'UTF-8');
parser.parseString(r, function (err, parsedData) {
if (err) throw err;
else {
fs.writeFile("jsonData.json", JSON.stringify(parsedData), function (err, response) {
});
}
});
done();
});
})
My sample xml file :
<?xml version="1.0" encoding="UTF-8" ?>
<ALEXA>
<SD TITLE="A" FLAGS="" HOST="davidwalsh.name">
<TITLE TEXT="David Walsh Blog :: PHP, MySQL, CSS, Javascript, MooTools, and Everything Else"/>
<LINKSIN NUM="1102"/>
<SPEED TEXT="1421" PCT="51"/>
</SD>
<SD>
<POPULARITY URL="davidwalsh.name/" TEXT="7131"/>
<REACH RANK="5952"/>
<RANK DELTA="-1648"/>
</SD>
</ALEXA>
I'm getting the below output :
{
"ALEXA": {
"SD": [
{
"$": {
"TITLE": "A",
"FLAGS": "",
"HOST": "davidwalsh.name"
},
"TITLE": [
{
"$": {
"TEXT": "David Walsh Blog :: PHP, MySQL, CSS, Javascript, MooTools, and Everything Else"
}
}
],
"LINKSIN": [
{
"$": {
"NUM": "1102"
}
}
],
"SPEED": [
{
"$": {
"TEXT": "1421",
"PCT": "51"
}
}
]
},
{
"POPULARITY": [
{
"$": {
"URL": "davidwalsh.name/",
"TEXT": "7131"
}
}
],
"REACH": [
{
"$": {
"RANK": "5952"
}
}
],
"RANK": [
{
"$": {
"DELTA": "-1648"
}
}
]
}
]
}
}
'$' is getting added to the parsed json. How to avoid it..??
Looking for a solution. Thanks in advance.
The $ is the place for your attributes with the default config.
As xml2js parses your XML tags (SD for example) explicitly as arrays (with explicitArray=true - you either way have multiple of them, and you can only assign one similar key per object in JSON), you need a place to store the attributes, this is what $ is for. You can enforce creating arrays using (which is the default) or turn this off. Using mergeAttrs you might eventually get a result, that you desire.
You can change the attrkey if that would be one solution as well. The same goes for charkey and so on. You can find the whole config options in the README on GitHub at https://github.com/Leonidas-from-XIV/node-xml2js - eventually an option to transform to children might the right for you.
If you don't need attributes at all you can set ignoreAttrs=true. By the way; parser options go as an object into the parser constructor, in your case: new xml2js.Parser({...options});
library like this usually parse everything and sometimes resulting in having many properties which you don't need.
i created camaro for this purpose.
downside of this is you have to write your own template file for the structure you want xml to be transform to.
const transform = require('camaro')
const fs = require('fs')
const xml = fs.readFileSync('ean.xml', 'utf-8')
const template = {
cache_key: "/HotelListResponse/cacheKey",
hotels: ["//HotelSummary", {
hotel_id: "hotelId",
name: "name",
rooms: ["RoomRateDetailsList/RoomRateDetails", {
rates: ["RateInfos/RateInfo", {
currency: "ChargeableRateInfo/#currencyCode",
non_refundable: "nonRefundable",
price: "ChargeableRateInfo/#total"
}],
room_name: "roomDescription",
room_type_id: "roomTypeCode"
}]
}],
session_id: "/HotelListResponse/customerSessionId"
}
const result = transform(xml, template)
Instead xml2js, use xml2json which converts exactly from xml to json with the specific keys.

How can I do Routing in Azure Functions?

I know that I can use url parameters like this:
"myfunction?p=one&p2=two"
and in code that becomes
request.query.p = "one";
but I would prefer to get it like this (express routing style):
"myfunction/:myvalue"
and use this url:
/myfunction/nine
which becomes this in code:
request.params.myvalue = "nine"
but I can't seem to find how to configure a route path like that in Azure Functions, any ideas or docs?
We've shipped route support for HTTP Triggers in Azure Functions. You can now add a route property which follows ASP.NET Web API route naming syntax. (You can set it directly via the Function.json or via the portal UX)
"route": "node/products/{category:alpha}/{id:guid}"
Function.json:
{
"bindings": [
{
"type": "httpTrigger",
"name": "req",
"direction": "in",
"methods": [ "post", "put" ],
"route": "node/products/{category:alpha}/{id:guid}"
},
{
"type": "http",
"name": "$return",
"direction": "out"
},
{
"type": "blob",
"name": "product",
"direction": "out",
"path": "samples-output/{category}/{id}"
}
]
}
.NET sample:
public static Task<HttpResponseMessage> Run(HttpRequestMessage request, string category, int? id,
TraceWriter log)
{
if (id == null)
return req.CreateResponse(HttpStatusCode.OK, $"All {category} items were requested.");
else
return req.CreateResponse(HttpStatusCode.OK, $"{category} item with id = {id} has been requested.");
}
NodeJS sample:
module.exports = function (context, req) {
var category = context.bindingData.category;
var id = context.bindingData.id;
if (!id) {
context.res = {
// status: 200, /* Defaults to 200 */
body: "All " + category + " items were requested."
};
}
else {
context.res = {
// status: 200, /* Defaults to 200 */
body: category + " item with id = " + id + " was requested."
};
}
context.done();
}
Official docs: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook#url-to-trigger-the-function
Today, you'd have to use a service like Azure API Management to customize your routes.
There is a PR in progress to add custom routes to Azure Functions itself. The team is hoping it will land in the next release. https://github.com/Azure/azure-webjobs-sdk-script/pull/490
Note: I'm a PM on the Azure Functions team
azure-function-express
With azure-function-express you can use all expressjs functionalities including routing ;)
const createHandler = require("azure-function-express").createAzureFunctionHandler;
const express = require("express");
// Create express app as usual
const app = express();
app.get("/api/:foo/:bar", (req, res) => {
res.json({
foo : req.params.foo,
bar : req.params.bar
});
});
// Binds the express app to an Azure Function handler
module.exports = createHandler(app);
See more examples here including a way to handle all routes within a single Azure Function handler.
PS: Feel free to contribute to the project!

Resources