Angular Service with Azure Cosmos - node.js

I am really new to Angular. I am trying to create a service which i want to consume in my angular component. While doing so i am getting below error.
Below is my code which i am writing
import { Injectable } from '#angular/core';
import { HttpClient} from '#angular/common/http';
import { CosmosClient } from '#azure/cosmos';
import {Observable,of} from 'rxjs'
#Injectable({
providedIn: 'root'
})
export class ApiService {
databaseId='dbName';
containerId='Container Name';
constructor() { }
public async getProjects():Promise<Observable<any>>{
const endpoint = "https://AAAA.documents.azure.com:443/";
const key = "==";
const client = new CosmosClient({ endpoint, key });
const database = client.database(this.databaseId);
const container = database.container(this.containerId);
const querySpec = {query: "SELECT * from c where c.Category=\"Details\""};
const { resources:items } = await container.items.query(querySpec).fetchAll();
return of(items);
}
}
Any help is really appreciated.

There is an exception to every rule, but the use cases for connecting to a DB directly from a web browser are pretty close to zero. By doing so, you lose all fine grained control over what a user can do in your database and the only way to revoke access is to rotate your keys. You may not currently have anything in your database that is sensitive, but it is still considered bad practice.
For this reason, the CosmosDB library is compatible with NodeJS as a server-side framework. Whether or not it works with front end frameworks like Angular or React are incidental. There are some large changes in how Angular compiles projects in version 9, and it looks like the Cosmos client is not compatible with the new Ivy compiler.
You do have a couple options here.
(recommended) Use an API layer between your database and your front end. You can use Node to keep it within Javascript. If you are running on Azure, there are services like Azure Functions that can make this even easier to implement securely, or you can run it from the same App Service, VM, or whatever hosting solution you are using.
Disable the new Ivy compiler.You can do this by adding aot: false in your angular.json

Related

NestJs for lambda with mongodb creating too many connections

We are using nestjs for lambda which connects with mongodb for data. We are using nestjs mongoose module. However on deployment for each invocation a new set of connection are made and the previous ones are not released.
We are using forRootAsync
MongooseModule.forRootAsync({
useClass: MongooseConfigService,
})
service looks like this:
#Injectable({ scope: Scope.REQUEST })
export class MongooseConfigService implements MongooseOptionsFactory {
constructor(#Inject(REQUEST) private readonly request: Request) {}
async createMongooseOptions(): Promise<MongooseModuleOptions> {
if (Buffer.isBuffer(this.request.body)) {
this.request.body = JSON.parse(this.request.body.toString());
}
const { db } = this.request.body;
console.log('connecting database', db);
return {
uri: process.env.MONGO_URL,
dbName: db || '',
};
}
}
I understand we need to reuse the same connection. We have achieved it in nodejs by simply checking if the connection already exists and if it does not connect again. Not sure how to achieve the same in nest.js
tried changing the scope of service to Scope.DEFAULT but that didn't help.
I would suggest that you make a connection proxy for MongoDB. Ever time a lambda gets invoked, it will open up a new connection to MongoDB. AWS generally provides a service that allows you to proxy requests through one connect, this is a common issue with RDS etc.
This may help you though: https://www.mongodb.com/docs/atlas/manage-connections-aws-lambda/
We were able to resolve the issue by using a durable provider. NestJs documentation we created a strategy at the root that would use a parameter coming in each request. NestJs would than call the connection module only when a new connection was required.
Note: When you use durable providers, Requests doesn't have all the parameters anymore and now only has the tenantId as per the example.

Application insights not logging Requests,Page views, Custom events

I have promoted my app from dev to stage environment App Service.
But now I cant see Page views,Custom events getting logged in my Application Insights which was logging fine in Dev.
Why is this happening?
Note:
1.I am using correct Instrumentation Key
2.Track calls are 200
3.The app is a Teams tab app built using React and using React plugin for App insights(working fine in dev)
4.Runtime Stack for dev environment was Node.Js but for Stage is .NET (Is this causing this issue?)
Also Note I have gone through all scenarios in Troubleshooting guide
Did the issue resolved for you ?
If not,
Ensure that you install the npm package for React.js,
npm install #microsoft/applicationinsights-react-js
npm install #microsoft/applicationinsights-web
Initialize a connection to Application Insights:
in AppInsights.js
import { ApplicationInsights } from '#microsoft/applicationinsights-web';
import { ReactPlugin } from '#microsoft/applicationinsights-react-js';
import { createBrowserHistory } from 'history';
const browserHistory = createBrowserHistory({ basename: '' });
const reactPlugin = new ReactPlugin();
const appInsights = new ApplicationInsights({
config: {
instrumentationKey: 'YOUR_INSTRUMENTATION_KEY_GOES_HERE',
extensions: [reactPlugin],
extensionConfig: {
[reactPlugin.identifier]: { history: browserHistory }
}
}
});
appInsights.loadAppInsights();
export { reactPlugin, appInsights };
And then Wrap your component with the higher-order component function to enable Application Insights on it:
import React from 'react';
import { withAITracking } from '#microsoft/applicationinsights-react-js';
import { reactPlugin, appInsights } from './AppInsights';
// To instrument various React components usage tracking, apply the `withAITracking` higher-order
// component function.
class MyComponent extends React.Component {
...
}
// withAITracking takes 4 parameters ( reactPlugin, Component, ComponentName, className)
// the first two are required and the other two are optional.
export default withAITracking(reactPlugin, MyComponent);
This will help you track all the requests, page views and custom events.
Also take a look at this doc for more reference : Javascript React SDK Plugin
Turns out it was a problem with the Application Insights instance itself and not in code or App service configuration.
When ever you face such problem where problem is not with code or App service,please reach out to your organization's support Team.

React native and IBM Watson

I have been using expo to build a react native app and would like to integrate an IBM Watson chatbot onto my platform. When I import the module however I receive a lot of error messages as core node modules such as os and fs seem to be missing, but aren't downloaded with node.js for some reason. When I try and add these manually, the HTTPS module is missing the index.js file. Is there any way for me to find this file or resolve this problem another way?
It's not completely clear from your question but I shall assume that you are using the Node SDK for Watson Assistant. This is designed to be run in a Node.js environment which a react native JavaScript bundle is not (with or without expo). That's why you are missing key libraries like os and fs which the Node SDK expects. Installing fs won't resolve your problem because it also expects a Node.js environment to work, hence why there are react native specific fs libraries that are able to use ios and android code to interact with the file system of the phone.
What you should be attempting is running the Node SDK on an independent server and running simple api requests using libraries like axios or for more robust production systems graphql so that your architecture will approximate this high level design.
a high level architecture diagram which shows a phone connected by an arrow reading axios api request to another box labelled cloud hosted server. From this box another arrow labelled Node SDK is pointing to another box labelled Watson Assistant
Web applications are similarly limited. The code run on the user's browsers can't directly use the Watson Assistant SDK, these requests to Watson Assistant need to be run by a server. There is an example starter Watson Assistant web application that does this. If you run or host this application you can use the same server for your requests (although bear in mind this simple app and shared traffic probably isn't scalable for anything but a proof of concept).
So rather than running the api requests to Watson Assistant directly you run them to this domain of the server and then the necessary endpoint. The server in the example app is set up to accept requests to start the session at <your domain>/api/session and to send messages at <your domain>/api/message
You optionally can run direct api calls to Watson Assistant from a react native app without the SDK. It's not advisable because you would need to store your private keys on the device where they could be viewed by anyone.
Here is a functional component that is able to complete api calls direct to Watson Assistant using the v1 of the message tool without the SDK. BUT IT IS NOT ADVISED BECAUSE I MUST STORE MY KEYS INSECURELY.
import React, { useState } from 'react';
import { View, Text, TouchableOpacity } from 'react-native';
import axios from 'axios';
import base64 from 'react-native-base64';
const workspace = ''; //replace with your own workspace id
const key = ''; //replace with your own key
const encodedKey = base64.encode(`apikey:${key}`);
// the following url will be different depending on where you host your Watson Assistant
// this is for Frankfurt as an example hence eu-de in the domain name
const assistantInstance =
'https://api.eu-de.assistant.watson.cloud.ibm.com/instances/<This is your own>/v1'; //replace with your own
const ExampleComponent = () => {
const [response, setResponse] = useState('');
const sendMessage = () => {
axios
.post(
`${assistantInstance}/workspaces/${workspace}/message?version=2018-09-20`,
{
input: { text: 'This is the message' },
},
{
headers: {
Authorization: `Basic ${encodedKey}`,
'Content-Type': 'application/json',
},
},
)
.then((data: any) => {
console.log(data);
setResponse('Got response');
})
.catch((err: any) => {
console.log(err);
setResponse('Got an error');
});
};
return (
<View>
<Text>{response}</Text>
<TouchableOpacity
onPress={() => {
sendMessage();
}}
>
Send message
</TouchableOpacity>
</View>
);
};
export default ExampleComponent;
The next complication you will find is that you will need to add code to store the context returned in the response otherwise your state is lost. Your body would end up looking something like
{
input: { text: 'This is the message' },
context: savedContextObject
},
The newer version of the API has a stateful version which you may want to use instead. You can use this axios as a pattern for constructing whatever requests your prefer.
For the third and final time PLEASE DO NOT SAVE TO THE JS FILE YOUR API KEY as I do here. This is just as an example and for proof of concepts. Anyone who downloads your app will be able to unzip your apk and read these strings in your generated JS bundle unencrypted!

Storing token on server-side using nestjs

I have a nestjs application that consumes third party API for data. In order to use that third party API, I need to pass along an access token. This access token is application-wide and not attached to any one user.
What would be the best place to store such a token in Nestjs, meeting the following requirements:
It must be available in the application and not per given user
It must not be exposed to the frontend application
It must work in a load balancer setup
I am looking at Nestjs caching https://docs.nestjs.com/techniques/caching, but I am not sure whether that's the best practice and if it is - should I use it with in-memory storage or something like redis.
Thank you.
If you're working with Load Balancing, then in-memory solutions are dead on arrival, as they will only affect one instance of your server, not all of them. Your best bet for speed purposes and accessibility would be Redis, saving the token under a simple key and keeping it alive from there (and updating it as necessary). Just make sure all your instances connect to the same Redis instance, and that your instance can handle it, shouldn't be a problem, more of a callout
I used a custom provider. Nest allows you to load async custom providers.
export const apiAuth = {
provide: 'API_AUTH',
useFactory: async (authService: AuthService) => {
return await authService.createOrUpdateAccessToken()
},
inject: [AuthService]
}
and below is my api client.
#Injectable()
export class ApiClient {
constructor(#Inject('API_AUTH') private auth: IAuth, private authService: AuthService) { }
public async getApiClient(storeId: string): Promise<ApiClient> {
if (((Date.now() - this.auth.createdAt.getTime()) > ((this.auth.expiresIn - 14400) * 1000))) {
this.auth = await this.authService.createOrUpdateAccessToken()
}
return new ApiClient(storeId, this.auth.accessToken);
}
}
This way token is requested from storage once and lives with the application, when expired token is re-generated and updated.

Use mongoose in an angular project

I try to integrate MongoDB in my project angular 6. I want to use the ODM Mongoose.
npm install mongoose --save
I created this service which must manage the connection with the database
import { Injectable } from '#angular/core';
import { mongoose } from 'mongoose';
#Injectable()
export class BD {
private bd;
public test: string;
constructor(mongoose: mongoose){}
Test(){
mongoose('the url of the database')
this.bd = mongoose.connection;
this.bd.on('error', console.error.bind(console, 'error: impossible connection to the database'));
this.bd.once('open', ()=>{console.log('connected to the DB :}')})
}
}
When I launch the application in my browser I have this erreur:
SCRIPT5009: 'global' is not defined
What does this error mean?
Is this how I have to import mongoose?
Thank you in advance for your help
Mongoose is a library designed specially for node.js and won't work in the browser environment. In order to be able to connect the db - you need to establish node.js back-end server, for example express.js. Then you will be able access your resources through the REST api.
Also, you cannot establish connection to the database directly, because you need somehow secure the data inside those database. When you connecting to the database directly - everyone who can take a look at your code will gain acess to the data and this is serious security problem.

Resources