express and moralis token price API not fetching json data in console - api

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.

Related

Fresh Framework: Fetching to own api results in "URL not found"

In my "/yourPage" route, my handler is trying to fetch "/api/joke" from my local database. I get "URL not found" error. Since Fresh is server rendered, I'd like to get all the data I need when loading the first time.
This works fine when fetching after initial load (like with a button).
As per its documentation, it should work fine, and does for any API that is not in its own repository.
Any way I can make this work? Am I thinking of this the wrong way?
The fetch inside my handler:
routes/yourPage.ts
export const handler: Handlers = {
async GET(req, ctx) {
const joke = await getJokes()
return ctx.render(joke);
},
};
/routes/api/joke.ts
const JOKES = [
"Why do Java developers often wear glasses? They can't C#.",
"A SQL query walks into a bar, goes up to two tables and says “can I join you?”",
];
export const handler = (_req: Request, _ctx: HandlerContext): Response => {
const randomIndex = Math.floor(Math.random() * JOKES.length);
const body = JOKES[randomIndex];
return new Response(body);
};
Pretty old post, but this is the first StackOverflow Google result when you try to search for API calling in Fresh Framework.
I am assuming you imported inside routes/yourPage.ts the handler from /routes/api/joke.ts as this:
import { handler as getJokes } from "./api/joke.ts";
Inside routes/yourPage.ts you also have to extract the text/json from the response before using it:
export const handler: Handlers = {
async GET(_req, _ctx) {
const response = getJokes(_req, _ctx);
const jokeText = await response.text();
return _ctx.render(jokeText);
},
};
Then you can use the response in your page as:
export default function Home({ data }: PageProps) { //...
Documentation here:
https://fresh.deno.dev/docs/getting-started/fetching-data

react-native (Expo) upload file on background

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.

Manipulate base64 file in expo

I need to manipulate this file I get in Base64 (download it or share it):
const generatePDF = async () => {
const companyReponse = await CompanyService.getCompany();
const peopleResponse = await PeopleService.getPerson(sale.customerId);
const company = companyReponse.response.company;
const people = peopleResponse.response;
const quote = false;
const json = await SaleService.generatePDF({
sale,
company,
people,
quote,
});
await ensureFolderExists();
if (json && json.success) {
const path = `${FileSystem.documentDirectory}MyFolder/Sale_${sale._id}.pdf`;
await FileSystem.writeAsStringAsync(path, json.data, {
encoding: FileSystem.EncodingType.Base64,
});
const url = `${FileSystem.documentDirectory}MyFolder/Sale_${sale._id}.pdf`;
Linking.openURL(url);
}
};
using the base64 string returns and searching like this in the browser data:application/pdf;base64,${json.data} I can even see it. but I've tried it in several ways and none of them worked, I believe this one may be closer to success.
[Unhandled promise rejection: Error: Could not open URL 'file:///data/user/0/host.exp.exponent/files/ExperienceData/%2540sensiogabriel%252FSensio/MyFolder/Sale_61a122679719d630dc416f91.pdf': file:///data/user/0/host.exp.exponent/files/ExperienceData/%2540sensiogabriel%252FSensio/MyFolder/Sale_61a122679719d630dc416f91.pdf exposed beyond app through Intent.getData()]
I solved this issue in this another ask
[https://stackoverflow.com/questions/69738812/problem-to-generate-pdf-from-a-blob-in-an-expo-app-using-filesystem][1]

React Native: Google OAuth Invalid parameter value for redirect_uri: Invalid scheme

I have some problems with authentication with Google OAuth2 in my react-native app. I'm using 'expo-auth-session' library for my authentification. I need get access token and then get Youtube profile. But i'm stuck with error "Invalid parameter value for redirect_uri: Invalid scheme"
My scheme in app.json:
"scheme": "com.liga.online"
My code is below:
import {
makeRedirectUri,
useAuthRequest,
ResponseType,
} from "expo-auth-session";
const discoveryYoutube = {
authorizationEndpoint: 'https://accounts.google.com/o/oauth2/v2/auth',
tokenEndpoint: 'https://oauth2.googleapis.com/token',
revocationEndpoint: 'https://oauth2.googleapis.com/revoke'
};
/// Inside my React component
const [requestYoutube, responseYoutube, promptAsyncYoutube] = useAuthRequest(
{
responseType: ResponseType.Code,
clientId: YOUTUBE_CLIENT_ID,
scopes: ["https://www.googleapis.com/auth/youtube.readonly"],
redirectUri: makeRedirectUri({
native: "com.liga.online/callback",
}),
},
discoveryYoutube
);
When I press the button, callback is starting
const signInYoutube = async () => {
const response = await promptAsyncYoutube();
console.log(response.data);
}
But I get error
Any idea how I can fix it?
P.S. I tried fix it with library "expo-google-app-auth". I get access token, but when I try to get Youtube profile and get "Request failed with status code 403".
UPDATE 1
By the way about my connection to Youtube Profile.
I change something to get access token.
For example:
import * as Google from 'expo-google-app-auth';
import { startAsync } from 'expo-auth-session';
// Inside my React component
// When I press the button, callback is starting
const signInYoutube = async () => {
const config = {
androidClientId: YOUTUBE_CLIENT_ID
};
const { type, accessToken, user } = await Google.logInAsync(config);
// I need again open my Browser for get Youtube data
const response = await startAsync({
authUrl: `https://www.googleapis.com/youtube/v3/channels?access_token=${accessToken}&part=snippet&mine=true&scope=https://www.googleapis.com/auth/youtube.readonly`,
showInRecents: true
});
console.log(response.data);
}
But I get error
UPDATE 2
I wanted to see which data is loaded from AuthRequest. And I see pretty weird log. Redirect_uri is different from the set.
RESOLUTION
When I add "https://www.googleapis.com/auth/youtube.readonly" in my scopes - i can get profile data. Another words below is my code.
import axios from 'axios';
import * as Google from 'expo-google-app-auth';
// Inside my React component
// Callback function
const signInYoutube = async () => {
const config = {
androidClientId: YOUTUBE_CLIENT_ID,
scopes: ['https://www.googleapis.com/auth/youtube.readonly']
};
const { type, accessToken, user } = await Google.logInAsync(config);
if (type === 'success') {
const response = await axios.get(
`https://www.googleapis.com/youtube/v3/channels?part=id&mine=true&key=${encodeURI(YOUTUBE_API_KEY)}`,
{
headers: {
Authorization: `Bearer ${accessToken}`
}
}
);
setYoutubeData({ accessToken, user, youtubeId: response.data.items[0].id });
}
};
IMPORTANT
Don't remember add in your project Youtube API v3
It looks like your expo environment is using the development redirect URI instead of the native one. Check out these docs for setting up the environment that will give you the native scheme you're looking for: https://docs.expo.io/guides/authentication/#standalone-bare-or-custom
Also make sure that you register your custom scheme with Google: https://developers.google.com/identity/protocols/oauth2/native-app#redirect-uri_custom-scheme
As for your Youtube example, you should be specifying the scopes in the call to Google.loginAsync, not the call to the Youtube API. scopes are requested during the authorization step, and your current authorization request doesn't include any. The relevant docs are here: https://docs.expo.io/versions/latest/sdk/google/#loginasync
REDIRECT URI
Your code looks roughly right though your redirect URI is a private URI scheme and should include a colon character:
com.liga.online:/callback
TRACING MESSAGES
For people to help you with your YouTube profile request you'll need to be able to tell us what is being sent over HTTP/S. Could you try to trace messages as in this write up of mine, then paste the request and response details into your question above

Error: Route.get() requires a callback function but got a [object Object] [duplicate]

So I'm starting to use Node.js. I saw the video with Ryan Dahl on Nodejs.org and heard he recommended Express-js for websites.
I downloaded the latest version of Express, and began to code. I have a fully fledged static view up on /, but as soon as I try sending parameters, I get errors like this:
Cannot GET /wiki
I tried following the guide on expressjs.com but the way one uses routes has changed in the latest version, which makes the guide unusable.
Guide:
app.get('/users/:id?', function(req, res, next){
var id = req.params.id;
if (id) {
// do something
} else {
next();
}
});
Generated by Express:
app.get('/', routes.index);
My problem arises when I try and add another route.
app.get('/wiki', routes.wiki_show);
I've tried a bunch of approaches, but I keep getting the Cannot GET /wiki (404) error.
routes/index.js looks like this:
exports.index = function(req, res) {
res.render('index', { title: 'Test', articles: articles, current_article: current_article, sections: sections })
};
The only thing I did there was add some parameters (arrays in the same file) and this i working. But when I copy the contents and change exports.index to exports.wiki or exports.wiki_show I still get the Cannot GET /wiki error.
Can anyone explain to me what I'm missing here? - Thanks.
So, after I created my question, I got this related list on the right with a similar issue: Organize routes in Node.js.
The answer in that post linked to the Express repo on GitHub and suggests to look at the 'route-separation' example.
This helped me change my code, and I now have it working. - Thanks for your comments.
My implementation ended up looking like this;
I require my routes in the app.js:
var express = require('express')
, site = require('./site')
, wiki = require('./wiki');
And I add my routes like this:
app.get('/', site.index);
app.get('/wiki/:id', wiki.show);
app.get('/wiki/:id/edit', wiki.edit);
I have two files called wiki.js and site.js in the root of my app, containing this:
exports.edit = function(req, res) {
var wiki_entry = req.params.id;
res.render('wiki/edit', {
title: 'Editing Wiki',
wiki: wiki_entry
})
}
The route-map express example matches url paths with objects which in turn matches http verbs with functions. This lays the routing out in a tree, which is concise and easy to read. The apps's entities are also written as objects with the functions as enclosed methods.
var express = require('../../lib/express')
, verbose = process.env.NODE_ENV != 'test'
, app = module.exports = express();
app.map = function(a, route){
route = route || '';
for (var key in a) {
switch (typeof a[key]) {
// { '/path': { ... }}
case 'object':
app.map(a[key], route + key);
break;
// get: function(){ ... }
case 'function':
if (verbose) console.log('%s %s', key, route);
app[key](route, a[key]);
break;
}
}
};
var users = {
list: function(req, res){
res.send('user list');
},
get: function(req, res){
res.send('user ' + req.params.uid);
},
del: function(req, res){
res.send('delete users');
}
};
var pets = {
list: function(req, res){
res.send('user ' + req.params.uid + '\'s pets');
},
del: function(req, res){
res.send('delete ' + req.params.uid + '\'s pet ' + req.params.pid);
}
};
app.map({
'/users': {
get: users.list,
del: users.del,
'/:uid': {
get: users.get,
'/pets': {
get: pets.list,
'/:pid': {
del: pets.del
}
}
}
}
});
app.listen(3000);
Seems that only index.js get loaded when you require("./routes") .
I used the following code in index.js to load the rest of the routes:
var fs = require('fs')
, path = require('path');
fs.readdirSync(__dirname).forEach(function(file){
var route_fname = __dirname + '/' + file;
var route_name = path.basename(route_fname, '.js');
if(route_name !== 'index' && route_name[0] !== "."){
exports[route_name] = require(route_fname)[route_name];
}
});
You could also organise them into modules. So it would be something like.
./
controllers
index.js
indexController.js
app.js
and then in the indexController.js of the controllers export your controllers.
//indexController.js
module.exports = function(){
//do some set up
var self = {
indexAction : function (req,res){
//do your thing
}
return self;
};
then in index.js of controllers dir
exports.indexController = require("./indexController");
and finally in app.js
var controllers = require("./controllers");
app.get("/",controllers.indexController().indexAction);
I think this approach allows for clearer seperation and also you can configure your controllers by passing perhaps a db connection in.
No one should ever have to keep writing app.use('/someRoute', require('someFile')) until it forms a heap of code.
It just doesn't make sense at all to be spending time invoking/defining routings. Even if you do need custom control, it's probably only for some of the time, and for the most bit you want to be able to just create a standard file structure of routings and have a module do it automatically.
Try Route Magic
As you scale your app, the routing invocations will start to form a giant heap of code that serves no purpose. You want to do just 2 lines of code to handle all the app.use routing invocations with Route Magic like this:
const magic = require('express-routemagic')
magic.use(app, __dirname, '[your route directory]')
For those you want to handle manually, just don't use pass the directory to Magic.