I have below code to access secret manager
export interface ConfigData {
dbname:string;
dbuser:string;
}
I hvae json data in secret manager like
{
"dbname" : "dbname",
"dbuser" : "dbuser"
}
function
private static async fetchSecretData(){
let config_key = 'projects/xx/xx/xx/versions/latest';
const client = new SecretManagerServiceClient();
const [version] = await client.accessSecretVersion({name:config_key})
console.log(version.payload?.data )
return version.payload?.data?.toString() as unknown as ConfigData;
}
But I need to cast this as unknown as ConfigData,
I want to cast this ConfigData without making it unknown.
If there is no alternate to do this, then what is the best option to get the keys from this unknown object.
Thanks
Two remarks:
toString() will return a string representation of whatever data is, so casting this to any other type is not going work.
It looks like SecretManagerServiceClient is a part of the Google Cloud Secret Manager API. You don't have to provide your own types for those as the #google-cloud/secret-manager package already comes with its own type definitions.
From from this package, I can tell that the payload is typed like this:
/** Properties of a SecretPayload. */
interface ISecretPayload {
/** SecretPayload data */
data?: (Uint8Array|string|null);
}
To me it's not quite clear what this data is supposed to be. If it's a JSON string then you need to parse it with JSON.parse(version.payload.data) and then append as ConfigData to that, to let TypeScript know the shape of the output. If it's a Uint8Array you need to .toString it first before parsing it with JSON.parse.
So you would get something like:
private static async fetchSecretData() {
let config_key = 'projects/xx/xx/xx/versions/latest';
const client = new SecretManagerServiceClient();
const [version] = await client.accessSecretVersion({name:config_key})
if(version?.payload?.data) {
return JSON.parse(version.payload.data) as ConfigData
} else {
return null;
}
}
Related
I'm trying to retrieve the data sent from my android app that is formed like this.
I'm trying to do it on JavaScript. I originally did this on Java and it was something like this
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Chat chat = postSnapshot.getValue(Chat.class);
I want to do the same thing on JavaScript but failed when I'm trying to. What I have now is this
class Chat{
constructor(detail,file_name,is_phone,type,user_id){
this.detail = detail;
this.file_name = file_name;
this.is_phone = is_phone;
this.type = type;
this.user_id = user_id;
}
detail(){ return this.detail;}
file_name(){ return this.file_name;}
is_phone(){ return this.is_phone;}
type(){ return this.type;}
user_id(){ return this.user_id;}
}
//Sync obj changes
dbRefObj.on('child_added',snap => {
myChat = new Chat (snap.val());
console.log(myChat);
});
But what I got is everything being set to detail...
The issue here seems to be that you want to spread the values, instead you're just assigning to the first parameter:
In the current implementation snap.val() is assigned to the detail param
class Chat{
constructor(detail, file_name, is_phone, type, user_id){
// ...
}
}
The following implementation will take the corresponding values from inside the snap.val()
class Chat{
constructor({ detail, file_name, is_phone, type, user_id}) {
// The difference is the use of the deconstructive syntax
}
}
I am passing a string from Javascript to a React Native native Java module and then back to Javascript. However, any high Unicode characters such as emojis become corrupted after passing it to Java and turn into a pair of question marks.
For example, the string "testing123😃" becomes "testing123??"
How can I fix this so that the characters retain their values?
EDIT: The string is being processed by a React Native background upload library. Here is an excerpt of the code from that library that passes the text (which is in the parameters field) to the Java module:
import { NativeModules, DeviceEventEmitter } from 'react-native'
export type StartUploadArgs = {
url: string,
path: string,
method?: 'PUT' | 'POST',
// Optional, because raw is default
type?: 'raw' | 'multipart',
// This option is needed for multipart type
field?: string,
customUploadId?: string,
// parameters are supported only in multipart type
parameters?: { [string]: string },
headers?: Object,
notification?: NotificationArgs
}
const NativeModule = NativeModules.VydiaRNFileUploader || NativeModules.RNFileUploader // iOS is VydiaRNFileUploader and Android is NativeModules
//...
export const startUpload = (options: StartUploadArgs): Promise<string> => NativeModule.startUpload(options)
And here is an excerpt of the Java code that handles the string:
#ReactMethod
public void startUpload(ReadableMap options, final Promise promise) {
//...
HttpUploadRequest<?> request;
if (requestType.equals("raw")) {
request = new BinaryUploadRequest(this.getReactApplicationContext(), customUploadId, url)
.setFileToUpload(filePath);
} else {
if (!options.hasKey("field")) {
promise.reject(new IllegalArgumentException("field is required field for multipart type."));
return;
}
if (options.getType("field") != ReadableType.String) {
promise.reject(new IllegalArgumentException("field must be string."));
return;
}
request = new MultipartUploadRequest(this.getReactApplicationContext(), customUploadId, url)
.addFileToUpload(filePath, options.getString("field"));
}
request.setMethod(method)
.setMaxRetries(2)
.setDelegate(statusDelegate);
//...
if (options.hasKey("parameters")) {
if (requestType.equals("raw")) {
promise.reject(new IllegalArgumentException("Parameters supported only in multipart type"));
return;
}
ReadableMap parameters = options.getMap("parameters");
ReadableMapKeySetIterator keys = parameters.keySetIterator();
while (keys.hasNextKey()) {
String key = keys.nextKey();
if (parameters.getType(key) != ReadableType.String) {
promise.reject(new IllegalArgumentException("Parameters must be string key/values. Value was invalid for '" + key + "'"));
return;
}
request.addParameter(key, parameters.getString(key));
}
}
//...
String uploadId = request.startUpload();
promise.resolve(uploadId);
}
The java servlet specification assumes form params are ISO-8859-1 by default. Assuming you are using tomcat see https://cwiki.apache.org/confluence/display/TOMCAT/Character+Encoding for info on how to resolve this issue
Relevant quote from the page
POST requests should specify the encoding of the parameters and values
they send. Since many clients fail to set an explicit encoding, the
default used is US-ASCII for application/x-www-form-urlencoded and
ISO-8859-1 for all other content types.
Related SO post https://stackoverflow.com/a/19409520/1967484
Keep in mind its also possible for your console and your database to also not support high unicode characters.
Modifying the background upload library's code like this fixed the issue:
request = new MultipartUploadRequest(this.getReactApplicationContext(), customUploadId, url)
.addFileToUpload(filePath, options.getString("field"))
.setUtf8Charset(); // add this line
Currently cleaning up a bit of code and rewritting a lot in typescript. What I found what made me curious is the following code:
const userRef = firestore.collection('users').doc(userId);
const userDoc = await userRef.get();
if (userDoc.exists) {
const userData = userDoc.data();
const currentUserBalance = userData.balance ? userData.balance : 0;
}
Now Typescript will complain that userData is possibily undefined, but the Documents .data() cannot be undefined when I check for the document existing above in my if block. Just curious on why that happens and if I have a logic issue here or not.
TypeScript doesn't have any knowledge of the relationship between exists and data(). It just knows the signature of data() says that the return value can be DocumentSnapshot or undefined. So, you must satisfy the compiler by either:
First checking for "truthiness", then use the results if so:
const data = userDoc.data()
if (data) {
// In this block, data is now typed as just DocumentData,
// undefined is no longer an option.
}
Telling TypeScript that you know for sure that the results will be "truthy" by using the ! operator:
const data = userDoc.data()! // data is now typed as just DocumentData
Unfortunately, even though Firestore adapters both for Node.js and the web are written mainly in TypeScript, they aren't designed for the language.
To solve the problem, I wrote Typesaurus, TypeScript-first ORM (or ODM if you wish) that solves this problem:
import { get, collection } from './src'
type User = { name: string }
const users = collection<User>('users')
async function main() {
const user = await get(users, 'qwe') // get will return document or undefined
if (user) {
console.log(user.data.name) // user is Doc<User>
} else {
// user is undefined
}
}
main()
I don't know why mongo mlab _id is not a string? I need to double check context and the viewer._id in my schema. This is my code:
resolve: async ({_id}, {status, ...args}, context) => {
// {_id} destructure _id property on root
console.log("allTodosByUser field = ",_id)
console.log("allTodosByUser field = ",context.user._id)
console.log("allTodosByUser equal",Boolean(_id.toString() === context.user._id.toString())) // suddenly using toString becomes true
This is not really a big deal but somehow I don't want to use toString for comparison:
if(_id.toString() === context.user._id.toString())
So I want to make a function maybe like this:
const { _id, context.user._id: contextUserId } = [_id, context.user._id], // push the _id, and context.user._id in an object so I can destructure?
Having problem with using forEach function with http requests.
I have a _watchlistElements variable, which holds following data:
[{"xid":"DP_049908","name":"t10"},{"xid":"DP_928829","name":"t13"},{"xid":"DP_588690","name":"t14"},{"xid":"DP_891890","name":"t16"},{"xid":"DP_693259","name":"t17"}]
Now, Im making a function which will download data from server for each of these xid elements:
private download() {
this._watchlistElements.forEach(v =>
this.http.get('http://localhost:8080/getValue/' + v.xid)
.subscribe(res => this._values = res.json()));
}
It has to download data as object for every v.xid value and store it inside the _values variable.
private _values: Array<WatchlistComponent> = [];
But somehow, angular returns an error with v.xid element. It doesn't see that variable. But it's kinda strange, because when I do it just in console, I mean: store that json inside a variable and use forEach function on this v.xid elements, everything works well.
ERROR in [default] C:\Users\src\app\appBody\watchlist\watchl
ist.component.ts:51:115
Property 'xid' does not exist on type 'WatchlistComponent'.
The xid exists... but inside the _watchlistElements which downloads the data asynchonously...
I'm not 100% sure this method is right, but if you have any ideas how to fix it, please tell me.
What happens when you print out the _values array?
The error above is a type error. What does the WatchlistComponent interface look like? Does it include an xid property?
You can get around the type error by overriding the type like...
private download() {
this._watchlistElements.forEach((v as any) =>
this.http.get('http://localhost:8080/getValue/' + v.xid)
.subscribe(res => this._values = res.json()));
}
As far as helping you structure your code better. If you want to combine the result of many Observables, I would use something like forkJoin.
private download():void {
//create an array of Observables
let el$ = _watchlistElements.map(el => {
return this.http.get('http://localhost:8080/getValue/' + el.xid)
.map(res: Response => <any>res.json());
});
//subscribe to all, and store the data, el$ is an array of Observables
Observable.forkJoin(el$).subscribe( data => {
this._values = data; //data will be structured as [res[0], res[1], ...]
});
}
HERE is a Plunker with the above method working. https://plnkr.co/edit/woXUIDa0gc55WJPOZMKh?p=preview
Related: angular2 rxjs observable forkjoin