I've been following video link from Moralis web3 (youtube) meanwgile I got stuck when I need to fetch data using token price Moralis API. I want the price details to be printed in the console when i do
npm start
the expected output in console is:
{
nativePrice: {
value: '13851123944545175839',
decimals: 18,
name: 'Ether',
symbol: 'ETH'
},
usdPrice: 23176.58785953117,
exchangeAddress: '0x1f98431c8ad98523631ae4a59f267346ea31f984',
exchangeName: 'Uniswap v3'
}
In localhost it should return empty json object '{}' but when I opened the same in localhost it is showing:
Cannot GET /tokenPrice
I tried different method provided in moralis doc its working fine but I did same as the tutorial that throws me error:
const express = require("express");
const Moralis = require("moralis").default;
const { EvmChain } = require("#moralisweb3/common-evm-utils");
const app = express();
const cors = require("cors");
require("dotenv").config();
const port = 3001;
app.use(cors());
app.use(express.json());
app.get("./tokenPrice", async (req, res) => {
const { query } = req;
const responseOne = await Moralis.EvmApi.token.getTokenPrice({
address: query.addressOne,
});
const responseTwo = await Moralis.EvmApi.token.getTokenPrice({
address: query.addressTwo,
});
console.log(responseOne.raw);
console.log(responseTwo.raw);
return res.status(200).json({});
});
Moralis.start({
apiKey: process.env.MORALIS_KEY,
}).then(() => {
app.listen(port, () => {
console.log(`Listening for API Calls`);
});
});
also I want to know what does that {query} & addressOne means here as I've never declared any var like before in my code.
I want to know what {query} and addressOne is , whether express js property or moralis
want to know why and where error occured and solution to resolve.
For addressOne and addressTwo, those are the query parameters used in your request. If you check the video you can see him showcasing an example of how the request should look like:
http://localhost:3001/tokenPrice?addressOne=0x51491...cf986ca&addressTwo=0xdac17f...6994597
And use 2 addresses of the tokens you wish to get the price for. You can indeed extend the logic to use more addresses
In the video at minute 45:00 You can see how the code should look like. Please make sure you complete your code for it to work properly.
I'm able to pickup the document from file system using expo-document-picker but can't figure out a way to save it. Please guide on this.
import * as DocumentPicker from 'expo-document-picker';
import * as FileSystem from 'expo-file-system';
const pickDocument = async () => {
let result = await DocumentPicker.getDocumentAsync({});
console.log(result); // was able to get result here
saveDocument(result);
};
const saveDocument = async (image) => {
const fileUri = `${FileSystem.documentDirectory}${image.name}`;
// const savedImage = await FileSystem.downloadAsync(image.uri, fileUri);
const savedImage = await FileSystem.moveAsync(image.uri, fileUri);
console.log('saved image', savedImage);
};
Read about expo file system, https://docs.expo.dev/versions/v46.0.0/sdk/filesystem/#filesystemdocumentdirectory
but couldn't find a method which helps save the document. Tried FileSystem.moveAsync but it gave below error:
Error: An exception was thrown while calling `ExponentFileSystem.moveAsync` with arguments `(
"file:///var/mobile/Containers/...
In my Expo (react-native) application, I want to do the upload task even if the application is in the background or killed.
the upload should be done to firebase storage, so we don't have a REST API.
checked out the Expo task manager library, but I could not figure out how it should be done. is it even possible to achieve this goal with Expo? is the TaskManager the correct package for this task?
there are only some Expo packages that could be registered as a task (e.g. backgroundFetch), and it is not possible to register a custom function (in this case uploadFile method).
I even got more confused as we should enable add UIBackgroundModes key for iOS but it only has audio,location,voip,external-accessory,bluetooth-central,bluetooth-peripheral,fetch,remote-notification,processing as possible values.
I would appreciate it if you can at least guide me on where to start or what to search for, to be able to upload the file even if the app is in the background is killed/terminated.
import { getStorage, ref, uploadBytes } from "firebase/storage";
const storage = getStorage();
const storageRef = ref(storage, 'videos');
const uploadFile = async (file)=>{
// the file is Blob object
await uploadBytes(storageRef, file);
}
I have already reviewed react-native-background-fetch, react-native-background-upload, react-native-background-job . upload should eject Expo, job does not support iOS, and fetch is a fetching task designed for doing task in intervals.
if there is a way to use mentioned libraries for my purpose, please guide me :)
to my understanding, the Firebase Cloud JSON API does not accept files, does it ? if so please give me an example. If I can make storage json API work with file upload, then I can use Expo asyncUpload probably without ejecting.
I have done something similar like you want, you can use expo-task-manager and expo-background-fetch. Here is the code as I used it. I Hope this would be useful for you.
import * as BackgroundFetch from 'expo-background-fetch';
import * as TaskManager from 'expo-task-manager';
const BACKGROUND_FETCH_TASK = 'background-fetch';
const [isRegistered, setIsRegistered] = useState(false);
const [status, setStatus] = useState(null);
//Valor para que se ejecute en IOS
BackgroundFetch.setMinimumIntervalAsync(60 * 15);
// Define the task to execute
TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => {
const now = Date.now();
console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`);
// Your function or instructions you want
return BackgroundFetch.Result.NewData;
});
// Register the task in BACKGROUND_FETCH_TASK
async function registerBackgroundFetchAsync() {
return BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, {
minimumInterval: 60 * 15, // 1 minutes
stopOnTerminate: false, // android only,
startOnBoot: true, // android only
});
}
// Task Status
const checkStatusAsync = async () => {
const status = await BackgroundFetch.getStatusAsync();
const isRegistered = await TaskManager.isTaskRegisteredAsync(
BACKGROUND_FETCH_TASK
);
setStatus(status);
setIsRegistered(isRegistered);
};
// Check if the task is already register
const toggleFetchTask = async () => {
if (isRegistered) {
console.log('Task ready');
} else {
await registerBackgroundFetchAsync();
console.log('Task registered');
}
checkStatusAsync();
};
useEffect(() => {
toggleFetchTask();
}, []);
Hope this isn't too late to be helpful.
I've been dealing with a variety of expo <-> firebase storage integrations recently, and here's some info that might be helpful.
First, I'd recommend not using the uploadBytes / uploadBytesResumable methods from Firebase. This Thread has a long ongoing discussion about it, but basically it's broken in v9. Maybe in the future the Firebase team will solve the issues, but it's pretty broken with Expo right now.
Instead, I'd recommend either going down the route of writing a small Firebase function that either gives a signed-upload-url or handles the upload itself.
Basically, if you can get storage uploads to work via an http endpoint, you can get any kind of upload mechanism working. (e.g. the FileSystem.uploadAsync() method you're probably looking for here, like #brentvatne pointed out, or fetch, or axios. I'll show a basic wiring at the end).
Server Side
Option 1: Signed URL Upload.
Basically, have a small firebase function that returns a signed url. Your app calls a cloud function like /get-signed-upload-url , which returns the url, which you then use. Check out: https://cloud.google.com/storage/docs/access-control/signed-urls for how you'd go about this.
This might work well for your use case. It can be configured just like any httpsCallable function, so it's not much work to set up, compared to option 2.
However, this doesn't work for the firebase storage / functions emulator! For this reason, I don't use this method, because I like to intensively use the emulators, and they only offer a subset of all the functionalities.
Option 2: Upload the file entirely through a function
This is a little hairier, but gives you a lot more fidelity over your uploads, and will work on an emulator! I like this too because it allows doing upload process within the endpoint execution, instead of as a side effect.
For example, you can have a photo-upload endpoint generate thumbnails, and if the endpoint 201's, then you're good! Rather than the traditional Firebase approach of having a listener to cloud storage which would generate thumbnails as a side effect, which then has all kinds of bad race conditions (checking for processing completion via exponentiational backoff? Gross!)
Here are three resources I'd recommend to go about this approach:
https://cloud.google.com/functions/docs/writing/http#multipart_data
https://github.com/firebase/firebase-js-sdk/issues/5848
https://github.com/mscdex/busboy
Basically, if you can make a Firebase cloud endpoint that accepts a File within formdata, you can have busboy parse it, and then you can do anything you want with it... like upload it to Cloud Storage!
an outline of this:
import * as functions from "firebase-functions";
import * as busboy from "busboy";
import * as os from "os";
import * as path from "path";
import * as fs from "fs";
type FieldMap = {
[fieldKey: string]: string;
};
type Upload = {
filepath: string;
mimeType: string;
};
type UploadMap = {
[fileName: string]: Upload;
};
const MAX_FILE_SIZE = 2 * 1024 * 1024; // 2MB
export const uploadPhoto = functions.https.onRequest(async (req, res) => {
verifyRequest(req); // Verify parameters, auth, etc. Better yet, use a middleware system for this like express.
// This object will accumulate all the fields, keyed by their name
const fields: FieldMap = {};
// This object will accumulate all the uploaded files, keyed by their name.
const uploads: UploadMap = {};
// This will accumulator errors during the busboy process, allowing us to end early.
const errors: string[] = [];
const tmpdir = os.tmpdir();
const fileWrites: Promise<unknown>[] = [];
function cleanup() {
Object.entries(uploads).forEach(([filename, { filepath }]) => {
console.log(`unlinking: ${filename} from ${path}`);
fs.unlinkSync(filepath);
});
}
const bb = busboy({
headers: req.headers,
limits: {
files: 1,
fields: 1,
fileSize: MAX_FILE_SIZE,
},
});
bb.on("file", (name, file, info) => {
verifyFile(name, file, info); // Verify your mimeType / filename, etc.
file.on("limit", () => {
console.log("too big of file!");
});
const { filename, mimeType } = info;
// Note: os.tmpdir() points to an in-memory file system on GCF
// Thus, any files in it must fit in the instance's memory.
console.log(`Processed file ${filename}`);
const filepath = path.join(tmpdir, filename);
uploads[filename] = {
filepath,
mimeType,
};
const writeStream = fs.createWriteStream(filepath);
file.pipe(writeStream);
// File was processed by Busboy; wait for it to be written.
// Note: GCF may not persist saved files across invocations.
// Persistent files must be kept in other locations
// (such as Cloud Storage buckets).
const promise = new Promise((resolve, reject) => {
file.on("end", () => {
writeStream.end();
});
writeStream.on("finish", resolve);
writeStream.on("error", reject);
});
fileWrites.push(promise);
});
bb.on("close", async () => {
await Promise.all(fileWrites);
// Fail if errors:
if (errors.length > 0) {
functions.logger.error("Upload failed", errors);
res.status(400).send(errors.join());
} else {
try {
const upload = Object.values(uploads)[0];
if (!upload) {
functions.logger.debug("No upload found");
res.status(400).send("No file uploaded");
return;
}
const { uploadId } = await processUpload(upload, userId);
cleanup();
res.status(201).send({
uploadId,
});
} catch (error) {
cleanup();
functions.logger.error("Error processing file", error);
res.status(500).send("Error processing file");
}
}
});
bb.end(req.rawBody);
});
Then, that processUpload function can do anything you want with the file, like upload it to cloud storage:
async function processUpload({ filepath, mimeType }: Upload, userId: string) {
const fileId = uuidv4();
const bucket = admin.storage().bucket();
await bucket.upload(filepath, {
destination: `users/${userId}/${fileId}`,
{
contentType: mimeType,
},
});
return { fileId };
}
Mobile Side
Then, on the mobile side, you can interact with it like this:
async function uploadFile(uri: string) {
function getFunctionsUrl(): string {
if (USE_EMULATOR) {
const origin =
Constants?.manifest?.debuggerHost?.split(":").shift() || "localhost";
const functionsPort = 5001;
const functionsHost = `http://${origin}:${functionsPort}/{PROJECT_NAME}/${PROJECT_LOCATION}`;
return functionsHost;
} else {
return `https://{PROJECT_LOCATION}-{PROJECT_NAME}.cloudfunctions.net`;
}
}
// The url of your endpoint. Make this as smart as you want.
const url = `${getFunctionsUrl()}/uploadPhoto`;
await FileSystem.uploadAsync(uploadUrl, uri, {
httpMethod: "POST",
uploadType: FileSystem.FileSystemUploadType.MULTIPART,
fieldName: "file", // Important! make sure this matches however you want bussboy to validate the "name" field on file.
mimeType,
headers: {
"content-type": "multipart/form-data",
Authorization: `${idToken}`,
},
});
});
TLDR
Wrap Cloud Storage in your own endpoint, treat it like a normal http upload, everything plays nice.
I am trying to do something may or may not be possible.
I have a SQL file called "travel.sql" that I am trying to make an api out of, so I thought the simplest thing to do is to save the queries as strings in an array and then save the array of strings as a response for a node server(express.js)
so simply here's the code till now but this is returning nothing in postman and I don't know what's missing or not
I checked all the packages and they are installed properly
const express = require('express')
const fse = require( "fs-extra" );
const { join } = require( "path" );
const app = express()
const port = 3000
app.get('/sqlfile', (req, res) => {
const loadSqlQueries = async folderName => {
// determine the file path for the folder
const filePath = join( process.cwd(), travel );
// get a list of all the files in the folder
const files = await fse.readdir( filePath );
// only files that have the .sql extension
const sqlFiles = files.filter( f => f.endsWith( ".sql" ) );
// loop over the files and read in their contents
const queries = {};
for ( let i = 0; i < sqlFiles.length; i++ ) {
const query = fse.readFileSync( join( filePath, sqlFiles[ i ] ), { encoding: "UTF-8" } );
queries[ sqlFiles[ i ].replace( ".sql", "" ) ] = query;
console.log(queries)
}
return queries;
res.send(queries);
};
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
I'm not quite sure of what you are trying to achieve, But anyway You have multiple parts of your code need to be enhanced:
As a first proposal I suggest to add a "try and catch" to your code so you can know the errors you are facing.
You are creating a function expression "loadSqlQueries" which I think is not needed and it never runs as you are just creating it but you never used it.
As the function expression is not needed then also the "return" is not needed.
To be able to use "await" like here: const files = await fse.readdir( filePath ); You need to use it inside "async" function.
You are using "travel" here const filePath = join( process.cwd(), travel ); as a variable, you need to use it as a string like this const filePath = join( process.cwd(), "travel" );
I've applied the above mentioned changes, kindly read the comments I added to your code to catch the changes and here is the final code:
const express = require('express')
const fse = require("fs-extra");
const { join } = require("path");
const app = express()
const port = 3000
app.get('/sqlfile',
// add async to be able to use await
async (req, res) => {
// add try and catch block to your code to catch the errors
try {
// no need for the function expression which is never used
// const loadSqlQueries = async folderName => {
// determine the file path for the folder
//use travel as a string not a variable
const filePath = join(process.cwd(), "travel");
// get a list of all the files in the folder
const files = await fse.readdir(filePath);
// only files that have the .sql extension
const sqlFiles = files.filter(f => f.endsWith(".sql"));
// loop over the files and read in their contents
const queries = {};
for (let i = 0; i < sqlFiles.length; i++) {
const query = fse.readFileSync(join(filePath, sqlFiles[i]), { encoding: "UTF-8" });
queries[sqlFiles[i].replace(".sql", "")] = query;
console.log(queries)
}
// As the function expression is not used we will comment return
// return queries;
res.send(queries);
// }
} catch (error) {
console.log(error);
}
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
I need to pick files from onedrive and dropbox. Is there any npm modules available.
This is an old question, but I ran into the same issue. Spent a while finding the best solution.
Using an in-browser package react-native-inappbrowser and the deepLink functionality. I was able to solve the issue.
You will have to look at the OneDrive/Dropbox documentation for allowing a RedirectUI for a react-native app.
const redirectUrl = 'com.******.*******://auth'
export const tryDeepLinking = async () => {
const loginUrl =
'https://login.microsoftonline.com/common/oauth2/v2.0/authorize';
const redirectUrl = getDeepLink();
const url = `${loginUrl}?redirect_url=
${encodeURIComponent(redirectUrl,)}
&client_id=${encodeURIComponent('**********',)}
&response_type=${encodeURIComponent('token')}
&scope=${encodeURIComponent(
'openid Files.ReadWrite.All offline_access',
)}`;
try {
if (await InAppBrowser.isAvailable()) {
const result: any = await InAppBrowser.openAuth(url, redirectUrl, {
// iOS Properties
ephemeralWebSession: false,
// Android Properties
showTitle: false,
enableUrlBarHiding: true,
enableDefaultShare: false,
});
const paramsString = result.url.split('#')[1];
let params: any = {};
paramsString.split('&').forEach(kv => {
const keyValue = kv.split('=', 2);
params[keyValue[0]] = keyValue[1];
});
await setStorageAzureToken(params.access_token);
Alert.alert('Response', 'Success');
} else {
Alert.alert('InAppBrowser is not supported :/');
}
} catch (error) {
console.error(error);
Alert.alert('Something’s wrong with the app :(');
}
};
This is what I am using to get the OneDrive access token, from there you are able to use the https://graph.microsoft.com/v1.0/ api's to manage files.
You can try to use react-native-document-picker.