How to enable apiKey required to true using the aws-sdk? - node.js

I have been stuck here for too long. How do I enable API Key for the particular REST method using the aws-sdk? I could enable it using the console, but not finding a method to achieve this using the nodejs sdk. So basically want to setup the secret key for specified API Endpoint + Resource + Method.
In the following snapshot, I enabled the api-key required to true from the console.
Docs referred: AWS Nodejs Doc
Here is what I have been able to do so far:
// CREATE API KEY
async function create() {
try {
const apiKey = await apigateway.createApiKeyAsync({
enabled: true,
generateDistinctId: true,
name: NAME_OF_KEY
});
/**
* #see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/APIGateway.html#createUsagePlan-property
*/
// CREATE USAGE PLAN AND LINK API
const usagePlan = await apigateway.createUsagePlanAsync({
name: NAME_OF_USAGE_PLAN,
apiStages: [
{
apiId: API_ID,
stage: STAGE
},
/* more items */
],
quota: QUOTA_INFO,
throttle: THROTTLE_INFO
});
/**
* Creates a usage plan key for adding an existing API key to a usage plan.
*/
// LINK API KEY AND USAGE PLAN
await apigateway.createUsagePlanKeyAsync({
keyId: apiKey.id,
keyType: 'API_KEY',
usagePlanId: usagePlan.id
});
return Promise.resolve(apiKey);
} catch (err) {
return Promise.reject(err);
}
}

You need to call the function updateMethod to update your method request:
Reference: Class: AWS.APIGateway
var params = {
httpMethod: 'STRING_VALUE', /* required */
resourceId: 'STRING_VALUE', /* required */
restApiId: 'STRING_VALUE', /* required */
patchOperations: [
{
from: 'STRING_VALUE',
op: add | remove | replace | move | copy | test,
path: 'STRING_VALUE',
value: 'STRING_VALUE'
},
/* more items */
]
};
apigateway.updateMethod(params, function(err, data) {
if (err) console.log(err, err.stack); // an error occurred
else console.log(data); // successful response
});
So you can do the following:
var apigateway = new AWS.APIGateway({apiVersion: '2015-07-09'});
var params = {
httpMethod: 'POST',
resourceId: 'resource id',
restApiId: API_ID,
patchOperations: [
{
op: 'replace',
path: '/apiKeyRequired',
value: 'true' || 'false'
},
]
};
apigateway.updateMethod(params, function(err, data) {
if (err) cb(err, err.stack); // an error occurred
else cb(null, data); // successful response
});
Hope it helps!

Related

Cognito - Error: Invalid UserPoolId format

I am using AWS CDK to create a userpool and userpool client. I would like to be able to access the userpool id and userpool client id from a lambda once they have been created. I pass these two values to the lambda via environmental variables. Here is my code:
import { Construct } from 'constructs';
import {
IResource,
LambdaIntegration,
MockIntegration,
PassthroughBehavior,
RestApi,
} from 'aws-cdk-lib/aws-apigateway';
import {
NodejsFunction,
NodejsFunctionProps,
} from 'aws-cdk-lib/aws-lambda-nodejs';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import * as amplify from 'aws-cdk-lib/aws-amplify';
import {
aws_s3,
aws_ec2,
aws_rds,
aws_cognito,
aws_amplify,
Duration,
CfnOutput,
} from 'aws-cdk-lib';
export class FrontendService extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
const userPool = new aws_cognito.UserPool(this, 'userpool', {
userPoolName: 'frontend-userpool',
selfSignUpEnabled: true,
signInAliases: {
email: true,
},
autoVerify: { email: true },
});
const userPoolClient = new aws_cognito.UserPoolClient(
this,
'frontend-app-client',
{
userPool,
generateSecret: false,
}
);
const bucket = new aws_s3.Bucket(this, 'FrontendStore');
const nodeJsFunctionProps: NodejsFunctionProps = {
environment: {
BUCKET: bucket.bucketName,
DB_NAME: 'hospoFEDB',
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
USER_POOL_ID: userPool.userPoolId,
USER_POOL_CLIENT_ID: userPoolClient.userPoolClientId,
},
runtime: Runtime.NODEJS_14_X,
};
const registerLambda = new NodejsFunction(this, 'registerFunction', {
entry: 'dist/lambda/register.js',
memorySize: 1024,
...nodeJsFunctionProps,
});
const registerIntegration = new LambdaIntegration(registerLambda);
const api = new RestApi(this, 'frontend-api', {
restApiName: 'Frontend Service',
description: 'This service serves the frontend.',
});
const registerResource = api.root.addResource('register');
registerResource.addMethod('POST', registerIntegration);
}
}
Here is my lambda function and how I intend to use the USER_POOL_ID and USER_POOL_CLIENT_ID env variables:
import {
CognitoUserPool,
} from 'amazon-cognito-identity-js';
export const handler = async (event: any, context: any) => {
try {
console.log(process.env.USER_POOL_ID);
console.log(process.env.USER_POOL_CLIENT_ID);
const userPool = new CognitoUserPool({
UserPoolId: process.env.USER_POOL_ID as string,
ClientId: process.env.USER_POOL_CLIENT_ID as string,
});
return {
statusCode: 200,
};
} catch (error) {
if (error instanceof Error) {
const body = error.stack || (JSON.stringify(error, null, 2) as any);
return {
statusCode: 400,
headers: {},
body: JSON.stringify(body),
};
}
return {
statusCode: 400,
};
}
};
The idea with this setup is that I would create a cognito user pool and client then be able to pass those id's directly down. Currently if I run this locally via sam local start-api it generates the following USER_POOL_ID : Frontenduserpool87772999. If I try and use this id in the new CognitoUserPool({... part of my lambda function I get the following error:
Error: Invalid UserPoolId format.
If I deploy the app however and execute the lambda function from the deployed environment with the exact same code I get a USER_POOL_ID that looks more like: us-east-1_HAjkUj9hP. This works fine and I do not get the error above.
Should I assume that I can not create a user pool locally and will always have to point to the deployed user pool?
Should I assume that I can not create a user pool locally and will always have to point to the deployed user pool
Yes. See the docs: start-api creates an emulated local API endpoint and Lambda for local testing. It does not deploy or emulate other resources.
You can reference previously deployed AWS resources by passing a JSON file with the deployed physical values using the --env-vars flag.

How to make kuzzle-device-manager plugin API actions works?

I successfully installed and loaded kuzzle-device-manager in the backend file:
import { Backend } from 'kuzzle';
import { DeviceManagerPlugin } from 'kuzzle-device-manager';
const app = new Backend('playground');
console.log(app.config);
const deviceManager = new DeviceManagerPlugin();
const mappings = {
updatedAt: { type: 'date' },
payloadUuid: { type: 'keyword' },
value: { type: 'float' }
}
deviceManager.devices.registerMeasure('humidity', mappings)
app.plugin.use(deviceManager)
app.start()
.then(async () => {
// Interact with Kuzzle API to create a new index if it does not already exist
console.log(' started!');
})
.catch(console.error);
But when i try to use controllers from that plugin for example device-manager/device with create action i get an error output.
Here is my "client" code in js:
const { Kuzzle, WebSocket } = require("kuzzle-sdk")
const kuzzle = new Kuzzle(
new WebSocket('KUZZLE_IP')
)
kuzzle.on('networkError', error => {
console.error('Network Error: ', error);
})
const run = async () => {
try {
// Connects to the Kuzzle server
await kuzzle.connect();
// Creates an index
const result = await kuzzle.query({
index: "nyc-open-data",
controller: "device-manager/device",
action: "create",
body: {
model: "model-1234",
reference: "reference-1234"
}
}, {
queuable: false
})
console.log(result)
} catch (error) {
console.error(error.message);
} finally {
kuzzle.disconnect();
}
};
run();
And the result log:
API action "device-manager/device":"create" not found
Note: The nyc-open-data index exists and is empty.
We apologize for this mistake in the documentation, the device-manager/device:create method is not available because the plugin is using auto-provisioning until the v2.
You should send a payload to your decoder, the plugin will automatically provision the device if it does not exists https://docs.kuzzle.io/official-plugins/device-manager/1/guides/decoders/#receive-payloads

How to create and send a backchannel event with every message in bot framework?

I'm trying to access a session variable from the botbuilder middleware in send hook:
bot.use({
botbuilder: function (session, next) {
session.send(); // it doesn't work without this..
session.sendTyping();
console.log('session.userData', session.userData['UI_Changes']);
var reply = createEvent("UI_Changes", session.userData['UI_Changes'], session.message.address);
session.send(reply);
// session.userData['UI_Changes'] = {};
next();
},
send: function (event, next) {
// console.log('session.userData', session.userData['UI_Changes']);
// var reply = createEvent("UI_Changes", session.userData['UI_Changes'], session.message.address);
// session.send(reply);
// session.userData['UI_Changes'] = {};
next();
}
});
But since session is not available in send, how can I access the userData?
createEvent simply creates a backchannel event:
//Creates a backchannel event
const createEvent = (eventName, value, address) => {
var msg = new builder.Message().address(address);
msg.data.type = "event";
msg.data.name = eventName;
msg.data.value = value;
return msg;
}
I found this answer on stackoverflow:
send: function (message, next) {
bot.loadSessionWithoutDispatching(message.address,function (error,session){
console.log(session.userData);
});
next();
}
But, when I try to create an event and send it, I'm not able to access the address
bot.loadSessionWithoutDispatching(event.address, function (error,session){
console.log('session not null?', session !== null ? "yes" : "no");
if(session !== null){
console.log('session.userData', session.userData['UI_Changes'], 'address:', session);
var reply = createEvent("UI_Changes", session.userData['UI_Changes'], event.address); //undefined
session.send(reply);
session.userData['UI_Changes'] = {};
}
});
both session.message and event.address are undefined inside the callback function. How can I possibly do a workaround?
event has following content:
event: { type: 'message',
text: 'You reached the Greeting intent. You said \'hi\'.',
locale: 'en-US',
localTimestamp: '2018-06-21T14:37:12.684Z',
from: { id: 'Steves#4MRN9VFFpAk', name: 'Steves' },
recipient: { id: 'pruthvi', name: 'pruthvi' },
inputHint: 'acceptingInput' }
whereas outside the loadSessionWithoutDispatching function it has:
event outside { type: 'message',
agent: 'botbuilder',
source: 'directline',
textLocale: 'en-US',
address:
{ id: 'A7nrBS4yINt2607QtKpxOP|0000048',
channelId: 'directline',
user: { id: 'pruthvi', name: 'pruthvi' },
conversation: { id: 'A7nrBS4yINt2607QtKpxOP' },
bot: { id: 'Steves#4MRN9VFFpAk', name: 'Steves' },
serviceUrl: 'https://directline.botframework.com/' },
text: 'You reached the Greeting intent. You said \'hi\'.' }
I've used bot.loadSession instead of loadSessionWithoutDispatching and it works fine.
I've used bot.loadSession instead of loadSessionWithoutDispatching and it works fine.

JayData with WebAPI OData V4 returns undefined

I'm writting AWS lambda function in NodeJS to read the data from WebAPI OData V4 service (http://localhost/SomeService/$metadata)
I generated metadata file using JaySvcUtil and referenced the resulting file in Lambda function
'use strict';
let $data = require('jaydata');
let meta = require('./apiData');
exports.handler = function (event, context) {
var con = new DataContext({
name: 'oData',
oDataServiceHost: 'http://localhost/SomeService'
});
con.onReady(function () {
$data.Users.forEach(function(data) {
console.log(data.Id);
});;
};
Unfortunately, when onReady method is invoked, Users object is undefined as well as any other type exosed by my API.
Any idea what i'm doing wrong?
Turned out that generated code created by jaysvcutil doesn't work with nodejs.
Instead of using .extend, .define should be used as explained in the doc.
$data.Class.define('Project.User', $data.Entity, null, {
'UserID': { 'key': true, 'type': 'Edm.Int32', 'nullable': false, 'computed': true },
});
$data.Class.define('$Project.Types.Context', $data.EntityContext, null, {
Users: { type: $data.EntitySet, elementType: Project.User }
});
And context initialization callback should be defined as follows:
jayContext = new $Project.Types.Context({
name: 'oData',
oDataServiceHost: 'http://localhost/SomeService'
});
jayContext.onReady(function (serviceContext) {
serviceContext.Users.forEach(function (user) {
console.log(user.UserID);
});
context.done(null, 'Hello World');
});

Building Elastic Beanstalk with Node.js SDK

Has anyone created an elastic beanstalk application with the AWS javascript sdk? I've been able to update existing applications using grunt, that works really well. But as part of a continuous integration/continuous deployment project, we want to also create the app when it's not there. I find the documentation confusing, and in AWS's usual fashion, lacking in any kind of cohesive examples, that say, "do this, then this." If anyone has done this and can point me in the right direction, that would be a great help. At this point in time, I'm not sure whether it's a single step or multi step process.
So, here's a basic node package to build an app. I have uploaded a basic API app as a zip file, it doesn't much of anything. The idea is that once it's created, I can then update it using a grunt script - there are a couple of very good grunt modules that will do that, once it's created. But the initial creation was missing. Easy enough to add on more parameters to this now, too.
var applicationName = process.argv[2];
var environmentName = process.argv[3];
var regionName = process.argv[4];
var AWS = require('aws-sdk');
AWS.config.update({region: regionName});
var applicationParams = {
ApplicationName: applicationName
};
var environmentParams =
{
ApplicationName: applicationName, /* required */
EnvironmentName: environmentName, /* required */
VersionLabel: 'initial',
SolutionStackName: "64bit Amazon Linux 2015.03 v1.4.4 running Node.js",
CNAMEPrefix: applicationName,
Tier:
{
Version: " ",
Type: "Standard",
Name: "WebServer"
},
OptionSettings:
[
{
Namespace: 'aws:elasticbeanstalk:environment',
OptionName: 'EnvironmentType',
Value: 'SingleInstance'
},
{
Namespace: 'aws:autoscaling:launchconfiguration',
OptionName: 'EC2KeyName',
Value: 'MyPemFile'
},
{
Namespace: 'aws:autoscaling:launchconfiguration',
OptionName: 'IamInstanceProfile',
Value: 'aws-elasticbeanstalk-ec2-role'
},
{
Namespace: 'aws:autoscaling:launchconfiguration',
OptionName: 'InstanceType',
Value: 't1.micro'
}
],
};
var versionParams =
{
ApplicationName: applicationName, /* required */
VersionLabel: 'initial', /* required */
AutoCreateApplication: true,
SourceBundle:
{
S3Bucket: 'beanstalk-test-ff',
S3Key: 'test-app.zip'
}
};
var elasticbeanstalk = new AWS.ElasticBeanstalk();
elasticbeanstalk.createApplication(applicationParams, function(err, data)
{
console.log('Creating application');
console.log(data);
if (err)
{
if (err.message.indexOf("already exists") > -1)
{
console.log('Application already exists, continuing on');
}
else
{
console.log(err,err.stack); // an error occurred
}
}
else
{
elasticbeanstalk.createApplicationVersion(versionParams, function(err, data)
{
console.log('Creating application version....');
console.log(data);
if (err) console.log(err, err.stack); // an error occurred
else
{
elasticbeanstalk.createEnvironment(environmentParams, function(err, data)
{
console.log('Creating application environment....');
console.log(data);
if (err) console.log(err, err.stack); // an error occurred
});
}
});
}
});

Resources