Javascript aws lambda unexplained behaviour - javascript

In the following example, the lambda code works (the lambda factory class), but the api code does not. Any idea why that might be? The lambda code instantiates the expected outputs. But the API code creaates nothing. It doesn't fail. It just doesn't do anything... As a quick sanity check, I instantiated the same chunk of code in the main file, and that does work fine...
top level
import { LambdaFactory } from './factory-dev/lambda/lambda-factory';
import { ApiGatewayFactory2 } from './factory-dev/api-gateway/apiGW';
export class SnDevStack extends cdk.Stack {
constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// 1. Lambda
const lambdaFactory = new LambdaFactory(this, 'lambdaFactoryId');
const lambdaSigfoxSync = lambdaFactory.sigfoxSync('testing options');
// 2. Dev API
const apiGatewayFactory = new ApiGatewayFactory2(this, 'ApiGatewayFactoryId');
const api = apiGatewayFactory.getApi('testing options');
}
lambda factory class
import * as cdk from '#aws-cdk/core';
import * as lambda from '#aws-cdk/aws-lambda'; // need for Runtime
import * as lambda_nodejs from '#aws-cdk/aws-lambda-nodejs';
export class LambdaFactory extends cdk.Construct {
constructor (scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id);
}
private TAG:string = "sn-dev-";
public sigfoxSync(options: string): lambda_nodejs.NodejsFunction {
const testLambda = new lambda_nodejs.NodejsFunction(this, 'sigfox-sync', {
runtime: lambda.Runtime.NODEJS_12_X,
entry: 'lambda/sn-dev/sigfox-sync.js',
handler: 'handler',
functionName: this.TAG + 'sigfox-sync',
description: 'Get all devices from Sigfox API & Sync into dynamoDB.',
memorySize: 256,
timeout: cdk.Duration.seconds(720)
});
return testLambda;
}
}
api factory class
import * as cdk from '#aws-cdk/core';
import * as apiGateway from '#aws-cdk/aws-apigateway';
export class ApiGatewayFactory2 extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id);
}
public getApi(options: string):apiGateway.RestApi {
const api = new apiGateway.RestApi(this, 'sn-dev',
{
restApiName: 'sn-dev',
deploy: true,
defaultCorsPreflightOptions: {
allowOrigins: apiGateway.Cors.ALL_ORIGINS,
allowMethods: apiGateway.Cors.ALL_METHODS // this is also the default
},
});
return api;
}
}
To double check, the following works perfectly if I write it directly in the main file. Why on earth does it not work in the factory class????
const api = new apiGateway.RestApi(this, 'sn-dev',
{
restApiName: 'sn-dev',
deploy: true,
deployOptions: {
// documentationVersion: documentVersion
},
defaultCorsPreflightOptions: {
allowOrigins: apiGateway.Cors.ALL_ORIGINS,
allowMethods: apiGateway.Cors.ALL_METHODS // this is also the default
},
});

Looks like your ApiGatewayFactory2 is extending Stack it should extend Construct.
I think if you want to create a child stack you need to extend NestedStack.

Related

How do I import this commonJS module into my Typescript with the least amount of changes

We have a gRPC repo that has a JS implementation of creating a client.
/**
* Code generated by protoc-gen-twirp_js v5.0.0, DO NOT EDIT.
* source: domain_service/service.proto
*/
// import our twirp js library dependency
var createClient = require("twirp");
// import our protobuf definitions
var pb = require("./domain_service/service_pb.js");
Object.assign(module.exports, pb);
/**
* Creates a new DomainClient
*/
module.exports.createDomainClient = function(baseurl, extraHeaders, useJSON) {
var rpc = createClient(baseurl, "events.domain_service.Domain", "v5.0.0", useJSON, extraHeaders === undefined ? {} : extraHeaders);
return {
fireDomainEvent: function(data) { return rpc("FireDomainEvent", data, pb.FireDomainEventResponse); }
}
}
I created a d.ts file in the same folder using TS playground
export function createDomainClient(
baseurl: any,
extraHeaders: any,
useJSON: any
): {
fireDomainEvent: (data: any) => any;
};
But when I try to implement the code:
import { createDomainClient } from '#MyOrganization/package';
const client = new createDomainClient(
'https://my.url.com', '', false
);
I get the follow error: 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
I am simply trying to import the commonJS client into my Typescript project with making the least amount of changes on the gRPC repo side.
Either explicitly set any type for client
import { createDomainClient } from '#MyOrganization/package';
const client: any = new createDomainClient(
'https://my.url.com', '', false
);
Or add a construct signature to the type
How does interfaces with construct signatures work?

Accessing express-http-context in dependent module

Short form question:
We are trying to access the express-http-context in a dependent logger module of our main NodeJS service. However, we are getting it as undefined.
Context:
We are trying to tag all our logs with a requestId for each unique request in NodeJS. We have a logger module that wraps winston logger. This logger module is a separate package and is used across all our different NodeJs (Express) services.
Our winston logger wrapper file in our cf-logger-module is as follows:
import { omit } from 'lodash';
import { Logger, createLogger, format, transports, LeveledLogMethod } from 'winston';
import httpcontext from 'express-http-context';
import Sentry from 'winston-sentry-log';
import { ILoggerConfig } from '../interfaces/ILoggerConfig';
import { LevelCodes } from '../constants/LoggingLevels';
import ILoggerAdapter from '../interfaces/ILoggerAdapter';
import LoggerConfiguration from '../LoggerConfiguration';
export default class WinstonLogger implements ILoggerAdapter {
private readonly _logger: Logger;
private _config: ILoggerConfig;
private _moduleName: string;
private _loggingMethods: { [prop: number]: LeveledLogMethod };
public static createAdapter(moduleName: string, config: LoggerConfiguration): ILoggerAdapter {
return new WinstonLogger(moduleName, config);
}
public constructor(moduleName: string, loggerConfiguration: LoggerConfiguration) {
this._config = loggerConfiguration.config;
this._moduleName = moduleName;
const sentryOptions = {
config: {
dsn: 'https://b71e24c577604eab977dcf18720f1d5a#o1185085.ingest.sentry.io/6468703',
},
level: 'info',
};
this._logger = createLogger({
levels: LevelCodes,
transports: [new transports.Console({ level: this._config.logging.level }), new Sentry(sentryOptions)],
format: format.combine(
format.timestamp({ format: this._config.logging.timestamp.format }),
format.errors({ stack: this._config.logging.errors.stack }),
format.simple(),
format.colorize(),
format.printf(({ level, message, timestamp, ...metadata }) => {
const module = metadata.module;
const method = `${metadata.methodName}()`;
metadata = omit(metadata, 'module');
metadata = omit(metadata, 'methodName');
// console.log('Logger http context', httpcontext.get('reqId'));
return `${timestamp} [${module}:${method}] [${level}]: ${message} ${JSON.stringify(metadata)}`;
}),
),
});
/* istanbul ignore next */
this._loggingMethods = {
[LevelCodes.debug]: this._logger?.debug.bind(this._logger),
[LevelCodes.error]: this._logger?.error.bind(this._logger),
[LevelCodes.http]: this._logger?.http.bind(this._logger),
[LevelCodes.info]: this._logger?.info.bind(this._logger),
[LevelCodes.silly]: this._logger?.silly.bind(this._logger),
[LevelCodes.verbose]: this._logger?.verbose.bind(this._logger),
[LevelCodes.warn]: this._logger?.warn.bind(this._logger),
};
}
public logMessage(level: number, message: string, metadata?: object, error?: Error): void {
this._loggingMethods[level](message, this.process(metadata, error));
}
private process(metadata?: object, error?: Error): object {
/** Extract Service Name */
console.log('Logger http context', httpcontext.get('reqId'));
Object.assign(metadata, {
module: `${this._config.service.name}.${this._moduleName}`,
});
/** Extract Error */
if (error !== undefined) {
Object.assign(error, metadata);
}
/** TODO: Sanitize and metadata */
return error || metadata;
}
}
As you can see we are trying to access the reqID set using express-http-context.
Our nodeJs apps package.json dependencies look like:
"dependencies": {
"#coverforce-platform/cf-logger-module": "^1.0.26",
....
"express-http-context": "^1.2.4",
"express-ruid": "^1.1.4",
},
The app.ts looks like:
private initializeMiddlewares() {
this.app.use(cors({ origin: AppConfig.getValues().SERVICE.ORIGIN }));
this.app.use(hpp());
this.app.use(helmet());
this.app.use(compression());
this.app.use(express.json());
this.app.use(express.urlencoded({ extended: true }));
this.app.use(cookieParser());
this.app.use(httpcontext.middleware);
this.app.use(ruid({ setInContext: true, attribute: 'reqId' }));
this.app.use(Sentry.Handlers.requestHandler() as express.RequestHandler);
this.app.use(Sentry.Handlers.errorHandler());
this.app.use(Sentry.Handlers.tracingHandler());
}
and the server.ts is:
import 'reflect-metadata';
import { Container } from 'typedi';
import { LoggerFactory, ILogger } from '#coverforce-platform/cf-logger-module';
import { AppConfig } from '#coverforce-platform/cf-config-module';
import { ErrorResponseMiddleware } from '#coverforce-platform/cf-error-module';
import { SchemaValidationMiddleware } from '#coverforce-platform/cf-schema-validation-module';
import { AccountsServiceSchema } from '#coverforce-platform/cf-common-api-model';
import { accountsDatabaseLoader } from './dependencyInjection/accountsDatabase.dependency';
import { App } from './app';
import { ERROR_RESPONSE_MIDDLEWARE, SCHEMA_VALIDATION_MIDDLEWARE } from './constants/dependencyInjection.constants';
main();
async function main() {
const logger: ILogger = initLogger();
await initAppConfig(logger);
initializeDependencyInjection();
const app: App = Container.get(App);
app.listen();
}
However, in the logger the console.log('Http Context', httpcontext.get('reqId') is always returning undefined for the reqId field in the httpcontext. If we do the same within any class in the main service we are able to retrieve the httpcontext's reqId. However, we are not able to access it in the dependent package/module.

Inject service into NestJS guard

We use ThrottlerGuard in our NestJS application from #nestjs/throttler package to rate limit connections and it's implemented like this:
#Injectable()
export class RateLimiter extends ThrottlerGuard {
RATE_LIMIT_EXCEEDED = 'Rate limit exceeded.';
async handleRequest(context: ExecutionContext, limit: number, ttl: number) {
const wsData = context.switchToWs().getData();
const metadata: MetadataObject = wsData.internalRepr;
const clientTokenMetadata = metadata.get(TOKEN_NAME) as MetadataValue[];
const clientToken = clientTokenMetadata[0].toString();
const tokensArray = await this.storageService.getRecord(clientToken);
if (tokensArray.length >= limit) {
throw new RpcException({
code: Status.UNAVAILABLE,
message: this.RATE_LIMIT_EXCEEDED,
});
}
await this.storageService.addRecord(clientToken, ttl);
return true;
}
}
Now, I need to inject another service, let's say ConfigService with the usage of constructor, but because it is an extended class, I need to call super(); method which required three more original arguments inherited from ThrottlerGuard, but they are not exported from the package. Is there any other way to make it work besides the method with DI in constructor?
What you can do, instead of extending ThrottleGuard is injecting it in your constructor and call canActivate() in handleRequest(). Benefit when not extending you don'
I haven't tested this but you can try the following:
import {ExecutionContext, Injectable} from "#nestjs/common";
import {ConfigService} from "#nestjs/config";
import {InjectThrottlerStorage, ThrottlerGuard, ThrottlerStorage} from '#nestjs/throttler'
#Injectable()
export class RateLimiter {
constructor(
private throttle: ThrottlerGuard,
private configService: ConfigService,
#InjectThrottlerStorage() private storage: ThrottlerStorage) {
}
async handleRequest(context: ExecutionContext, limit: number, ttl: number) {
// TODO something with ConfigService
return this.throttle.canActivate(context);
}
}
ThrottleGuard source code

How to extract definitions inside aws-cdk typescript stack class constructor function into separate files?

Experimenting with aws-cdk and it's easy to see how the stack/backend construct class files could get quite large. In this cdk Stack class example (copied and pruned from the aws-cdk api-cors-lambda-crud-dynamodb example) is there an idiomatic way to extract the dynamodb, lambda and apigateway constructor definitions out of the stack class constructor function into separate files? They all take this as the first argument. I'd like to have a separate file for all the lambda defs, one for the db def, api gateway config, etc that are still referenced inside the main stack class. Is there a way to do this without having to create new classes for each of the definitions?
export class ApiLambdaCrudDynamoDBStack extends cdk.Stack {
constructor(app: cdk.App, id: string) {
super(app, id);
const dynamoTable = new dynamodb.Table(this, "items", {
partitionKey: {
name: "itemId",
type: dynamodb.AttributeType.STRING
},
tableName: "items"
});
const getOneLambda = new lambda.Function(this, "getOneItemFunction", {
code: new lambda.AssetCode("src"),
handler: "get-one.handler",
runtime: lambda.Runtime.NODEJS_10_X,
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "itemId"
}
});
const getAllLambda = new lambda.Function(this, "getAllItemsFunction", {
code: new lambda.AssetCode("src"),
handler: "get-all.handler",
runtime: lambda.Runtime.NODEJS_10_X,
environment: {
TABLE_NAME: dynamoTable.tableName,
PRIMARY_KEY: "itemId"
}
});
dynamoTable.grantReadWriteData(getAllLambda);
dynamoTable.grantReadWriteData(getOneLambda);
const api = new apigateway.RestApi(this, "itemsApi", {
restApiName: "Items Service"
});
const items = api.root.addResource("items");
const getAllIntegration = new apigateway.LambdaIntegration(getAllLambda);
items.addMethod("GET", getAllIntegration);
const singleItem = items.addResource("{id}");
const getOneIntegration = new apigateway.LambdaIntegration(getOneLambda);
singleItem.addMethod("GET", getOneIntegration);
}
}
Yeah you can separate them into their own stacks. 'LambdaStack', 'DynamoDbStack', etc.
Or you can have just separate 'helper' classes if you don't want it directly in the constructor. Here's a simple C# example:
public class ApiLambdaCrudDynamoDbStack : Stack
{
internal ApiLambdaCrudDynamoDbStack(Construct scope, string id) : base (scope, id)
{
var helper = new MyHelper();
helper.CreateTable(this, "My-Cool-Table");
}
}
public class MyHelper
{
public void CreateTable(Construct scope, string tableName)
{
var table = new Table(scope, "My-Table", new TableProps()
{
TableName = tableName
});
}
}

ES6 Singleton vs Instantiating a Class once

I see patterns which make use of a singleton pattern using ES6 classes and I am wondering why I would use them as opposed to just instantiating the class at the bottom of the file and exporting the instance. Is there some kind of negative drawback to doing this? For example:
ES6 Exporting Instance:
import Constants from '../constants';
class _API {
constructor() {
this.url = Constants.API_URL;
}
getCities() {
return fetch(this.url, { method: 'get' })
.then(response => response.json());
}
}
const API = new _API();
export default API;
Usage:
import API from './services/api-service'
What is the difference from using the following Singleton pattern? Are there any reasons for using one from the other? Im actually more curious to know if the first example I gave can have issues that I am not aware of.
Singleton Pattern:
import Constants from '../constants';
let instance = null;
class API {
constructor() {
if(!instance){
instance = this;
}
this.url = Constants.API_URL;
return instance;
}
getCities() {
return fetch(this.url, { method: 'get' })
.then(response => response.json());
}
}
export default API;
Usage:
import API from './services/api-service';
let api = new API()
I would recommend neither. This is totally overcomplicated. If you only need one object, do not use the class syntax! Just go for
import Constants from '../constants';
export default {
url: Constants.API_URL,
getCities() {
return fetch(this.url, { method: 'get' }).then(response => response.json());
}
};
import API from './services/api-service'
or even simpler
import Constants from '../constants';
export const url = Constants.API_URL;
export function getCities() {
return fetch(url, { method: 'get' }).then(response => response.json());
}
import * as API from './services/api-service'
The difference is if you want to test things.
Say you have api.spec.js test file. And that your API thingy has one dependency, like those Constants.
Specifically, constructor in both your versions takes one parameter, your Constants import.
So your constructor looks like this:
class API {
constructor(constants) {
this.API_URL = constants.API_URL;
}
...
}
// single-instance method first
import API from './api';
describe('Single Instance', () => {
it('should take Constants as parameter', () => {
const mockConstants = {
API_URL: "fake_url"
}
const api = new API(mockConstants); // all good, you provided mock here.
});
});
Now, with exporting instance, there's no mocking.
import API from './api';
describe('Singleton', () => {
it('should let us mock the constants somehow', () => {
const mockConstants = {
API_URL: "fake_url"
}
// erm... now what?
});
});
With instantiated object exported, you can't (easily and sanely) change its behavior.
Both are different ways.
Exporting a class like as below
const APIobj = new _API();
export default APIobj; //shortcut=> export new _API()
and then importing like as below in multiple files would point to same instance and a way of creating Singleton pattern.
import APIobj from './services/api-service'
Whereas the other way of exporting the class directly is not singleton as in the file where we are importing we need to new up the class and this will create a separate instance for each newing up
Exporting class only:
export default API;
Importing class and newing up
import API from './services/api-service';
let api = new API()
Another reason to use Singleton Pattern is in some frameworks (like Polymer 1.0) you can't use export syntax.
That's why second option (Singleton pattern) is more useful, for me.
Hope it helps.
Maybe I'm late, because this question is written in 2018, but it still appear in the top of result page when search for js singleton class and I think that it still not have the right answer even if the others ways works. but don't create a class instance.
And this is my way to create a JS singleton class:
class TestClass {
static getInstance(dev = true) {
if (!TestClass.instance) {
console.log('Creating new instance');
Object.defineProperty(TestClass, 'instance', {
value: new TestClass(dev),
writable : false,
enumerable : true,
configurable : false
});
} else {
console.log('Instance already exist');
}
return TestClass.instance;
}
random;
constructor() {
this.random = Math.floor(Math.random() * 99999);
}
}
const instance1 = TestClass.getInstance();
console.log(`The value of random var of instance1 is: ${instance1.random}`);
const instance2 = TestClass.getInstance();
console.log(`The value of random var of instance2 is: ${instance2.random}`);
And this is the result of execution of this code.
Creating new instance
The value of random var of instance1 is: 14929
Instance already exist
The value of random var of instance2 is: 14929
Hope this can help someone

Categories

Resources