I have implemented transactions using ETH, however, I want to exchange tokens between accounts. Here is my code
var postData = {"jsonrpc":"2.0","method":"eth_sendTransaction","params": [{"from":"0x52f273a06a420453aa5b33c4f175395c9a1fddd8", "to": data.ethAddress, "value": 1e18}], "id":1}
var url = 'http://localhost:8545/'
var options = {
method: 'post',
body: postData,
json: true,
url: url
}
request(options, function (err, res, body) {
if (err) {
console.error('error posting json: ', err)
throw err
}
var headers = res.headers
var statusCode = res.statusCode
console.log('headers: ', headers)
console.log('statusCode: ', statusCode)
console.log('body: ', body)
})
This is completing the transaction with 1 ETH being transferred between accounts. However, I want to setup this same action but with my custom token as the currency, not ETH. Any help would be greatly appreciated. Thanks
I am not sure if that is what you need... You can create a class or two either in C# or in JavaScript to reflect all your properties.
var whatever= {};
whatever.jsonrpc="2.0";
whatever.id=1;
whatever.method="eth_sendTransaction";
whatever.params= [];
whatever.params[0].from="0x52f273a06a420453aa5b33c4f175395c9a1fddd8";
whatever.params[0].to=data.ethAddress;
whatever.params[0].value=1e18;
whatever.params[0].currency="xxx";
etc
I understand that you want to send your token (currency) among different accounts. So, I imagine that you have created your own token and that you have developed your code (your Smart Contract).
If not, you should create it.
Then, you should deploy your code and start using it.
You have a tutorial about it here.
Related
I am using a Cloud Function to call another Cloud Function on the free spark tier.
Is there a special way to call another Cloud Function? Or do you just use a standard http request?
I have tried calling the other function directly like so:
exports.purchaseTicket = functions.https.onRequest((req, res) => {
fetch('https://us-central1-functions-****.cloudfunctions.net/validate')
.then(response => response.json())
.then(json => res.status(201).json(json))
})
But I get the error
FetchError: request to
https://us-central1-functions-****.cloudfunctions.net/validate
failed, reason: getaddrinfo ENOTFOUND
us-central1-functions-*****.cloudfunctions.net
us-central1-functions-*****.cloudfunctions.net:443
Which sounds like firebase is blocking the connection, despite it being a google owned, and therefore it shouldn't be locked
the Spark plan only allows outbound network requests to Google owned
services.
How can I make use a Cloud Function to call another Cloud Function?
You don't need to go through the trouble of invoking some shared functionality via a whole new HTTPS call. You can simply abstract away the common bits of code into a regular javascript function that gets called by either one. For example, you could modify the template helloWorld function like this:
var functions = require('firebase-functions');
exports.helloWorld = functions.https.onRequest((request, response) => {
common(response)
})
exports.helloWorld2 = functions.https.onRequest((request, response) => {
common(response)
})
function common(response) {
response.send("Hello from a regular old function!");
}
These two functions will do exactly the same thing, but with different endpoints.
To answer the question, you can do an https request to call another cloud function:
export const callCloudFunction = async (functionName: string, data: {} = {}) => {
let url = `https://us-central1-${config.firebase.projectId}.cloudfunctions.net/${functionName}`
await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data }),
})
}
(Note we are using the npm package 'node-fetch' as our fetch implementation.)
And then simply call it:
callCloudFunction('search', { query: 'yo' })
There are legitimate reasons to do this. We used this to ping our search cloud function every minute and keep it running. This greatly lowers response latency for a few dollars a year.
It's possible to invoke another Google Cloud Function over HTTP by including an authorization token. It requires a primary HTTP request to calculate the token, which you then use when you call the actual Google Cloud Function that you want to run.
https://cloud.google.com/functions/docs/securing/authenticating#function-to-function
const {get} = require('axios');
// TODO(developer): set these values
const REGION = 'us-central1';
const PROJECT_ID = 'my-project-id';
const RECEIVING_FUNCTION = 'myFunction';
// Constants for setting up metadata server request
// See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
const functionURL = `https://${REGION}-${PROJECT_ID}.cloudfunctions.net/${RECEIVING_FUNCTION}`;
const metadataServerURL =
'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenUrl = metadataServerURL + functionURL;
exports.callingFunction = async (req, res) => {
// Fetch the token
const tokenResponse = await get(tokenUrl, {
headers: {
'Metadata-Flavor': 'Google',
},
});
const token = tokenResponse.data;
// Provide the token in the request to the receiving function
try {
const functionResponse = await get(functionURL, {
headers: {Authorization: `bearer ${token}`},
});
res.status(200).send(functionResponse.data);
} catch (err) {
console.error(err);
res.status(500).send('An error occurred! See logs for more details.');
}
};
October 2021 Update: You should not need to do this from a local development environment, thank you Aman James for clarifying this
Despite of the question tag and other answers concern the javascript I want to share the python example as it reflects the title and also authentification aspect mentioned in the question.
Google Cloud Function provide REST API interface what incluse call method that can be used in another Cloud Function.
Although the documentation mention using Google-provided client libraries there is still non one for Cloud Function on Python.
And instead you need to use general Google API Client Libraries. [This is the python one].3
Probably, the main difficulties while using this approach is an understanding of authentification process.
Generally you need provide two things to build a client service:
credentials ans scopes.
The simpliest way to get credentials is relay on Application Default Credentials (ADC) library. The rigth documentation about that are:
https://cloud.google.com/docs/authentication/production
https://github.com/googleapis/google-api-python-client/blob/master/docs/auth.md
The place where to get scopes is the each REST API function documentation page.
Like, OAuth scope: https://www.googleapis.com/auth/cloud-platform
The complete code example of calling 'hello-world' clound fucntion is below.
Before run:
Create default Cloud Function on GCP in your project.
Keep and notice the default service account to use
Keep the default body.
Notice the project_id, function name, location where you deploy function.
If you will call function outside Cloud Function environment (locally for instance) setup the environment variable GOOGLE_APPLICATION_CREDENTIALS according the doc mentioned above
If you will call actualy from another Cloud Function you don't need to configure credentials at all.
from googleapiclient.discovery import build
from googleapiclient.discovery_cache.base import Cache
import google.auth
import pprint as pp
def get_cloud_function_api_service():
class MemoryCache(Cache):
_CACHE = {}
def get(self, url):
return MemoryCache._CACHE.get(url)
def set(self, url, content):
MemoryCache._CACHE[url] = content
scopes = ['https://www.googleapis.com/auth/cloud-platform']
# If the environment variable GOOGLE_APPLICATION_CREDENTIALS is set,
# ADC uses the service account file that the variable points to.
#
# If the environment variable GOOGLE_APPLICATION_CREDENTIALS isn't set,
# ADC uses the default service account that Compute Engine, Google Kubernetes Engine, App Engine, Cloud Run,
# and Cloud Functions provide
#
# see more on https://cloud.google.com/docs/authentication/production
credentials, project_id = google.auth.default(scopes)
service = build('cloudfunctions', 'v1', credentials=credentials, cache=MemoryCache())
return service
google_api_service = get_cloud_function_api_service()
name = 'projects/{project_id}/locations/us-central1/functions/function-1'
body = {
'data': '{ "message": "It is awesome, you are develop on Stack Overflow language!"}' # json passed as a string
}
result_call = google_api_service.projects().locations().functions().call(name=name, body=body).execute()
pp.pprint(result_call)
# expected out out is:
# {'executionId': '3h4c8cb1kwe2', 'result': 'It is awesome, you are develop on Stack Overflow language!'}
These suggestions don't seem to work anymore.
To get this to work for me, I made calls from the client side using httpsCallable and imported the requests into postman. There were some other links to https://firebase.google.com/docs/functions/callable-reference there were helpful. But determining where the information was available took a bit of figuring out.
I wrote everything down here as it takes a bit of explaining and some examples.
https://www.tiftonpartners.com/post/call-google-cloud-function-from-another-cloud-function
Here's an inline version for the 'url' might expire.
This 'should' work, it's not tested but based off of what I wrote and tested for my own application.
module.exports = function(name,context) {
const {protocol,headers} = context.rawRequest;
const host = headers['x-forwardedfor-host'] || headers.host;
// there will be two different paths for
// production and development
const url = `${protocol}://${host}/${name}`;
const method = 'post';
const auth = headers.authorization;
return (...rest) => {
const data = JSON.stringify({data:rest});
const config = {
method, url, data,
headers: {
'Content-Type': 'application/json',
'Authorization': auth,
'Connection': 'keep-alive',
'Pragma': 'no-cache,
'Cache-control': 'no-cache',
}
};
try {
const {data:{result}} = await axios(config);
return result;
} catch(e) {
throw e;
}
}
}
This is how you would call this function.
const crud = httpsCallable('crud',context);
return await crud('read',...data);
context you get from the google cloud entry point and is the most important piece, it contains the JWT token needed to make the subsequent call to your cloud function (in my example its crud)
To define the other httpsCallable endpoint you would write an export statement as follows
exports.crud = functions.https.onCall(async (data, context) => {})
It should work just like magic.
Hopefully this helps.
I found a combination of two of the methods works best
const anprURL = `https://${REGION}-${PROJECT_ID}.cloudfunctions.net/${RECEIVING_FUNCTION}`;
const metadataServerURL =
'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=';
const tokenUrl = metadataServerURL + anprURL;
// Fetch the token
const tokenResponse = await fetch(tokenUrl, {
method: "GET"
headers: {
'Metadata-Flavor': 'Google',
},
});
const token = await tokenResponse.text();
const functionResponse = await fetch(anprURL, {
method: 'POST',
headers: {
"Authorization": `bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({"imageUrl": url}),
});
// Convert the response to text
const responseText = await functionResponse.text();
// Convert from text to json
const reponseJson = JSON.parse(responseText);
Extending the Shea Hunter Belsky's answer I would love to inform you that the call to the metatdata server of google to fetch the authorization token would not work from local machine
Since fetch is not readily available in Node.JS and my project was already using the axios library, I did it like this:
const url = `https://${REGION}-${PROJECT_ID}.cloudfunctions.net/${FUNCTION_NAME}`;
const headers = {
'Content-Type': 'application/json',
};
const response = await axios.post(url, { data: YOUR_DATA }, { headers });
I am trying to use zoho desk api in google apps script.
I am trying to genereate ticket through google script.But getting error.
Whereas if I do it in PHP its working fine.
Please find both codes for reference:
PHP CODE which is working
$auth_token = '12345ab';//your_auth_token
$org_id=12345; //your_organization_id
$ticket_data=array(
"departmentId"=>$getdepartmentid,
"contactId"=>$getcontactid,
"subject"=>$ticket_subject,
"description"=>$ticket_desc,
"priority"=>$priority,
"status"=>$ticketstatus,
"email"=>$contact_email,
"classification"=>$classification,
"channel"=>"Application"
);
$headers=array(
"Authorization: $auth_token",
"orgId: $org_id",
"contentType: application/json; charset=utf-8",
);
$url="https://desk.zoho.in/api/v1/tickets";
$ticket_data=(gettype($ticket_data)==="array")? json_encode($ticket_data):$ticket_data;
$ch= curl_init($url);
curl_setopt($ch,CURLOPT_HTTPHEADER,$headers);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch,CURLOPT_POST,TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS,$ticket_data); //convert ticket data array to json
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response= curl_exec($ch);
$info= curl_getinfo($ch);
GOOGLE APPS SCRIPT(which is not working)
var authtoken = "12345ab"; //your_auth_token
var org_id=12345; //your_organization_id
var department=23220000000057620; // ID of department
var contact=23220000000066959; //ID of customer
var subject=location_urgent_inbox_folder_name + ' /' + Name_of_file_to_be_attached;
var description="Ticked via drive";
var status="open";
const ticketData = {
subject: subject,
departmentId: department, // Replace this with whatever yours is.
contactId: contact, // Replace this with whatever yours is.
description: description,
status: status
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
var response = UrlFetchApp.fetch(zohoUrl, {
"method": 'POST',
"muteHttpExceptions": true,
"headers": {
Authorization: authtoken,
orgId: org_id,
contentType: 'application/json',
},
"payload": JSON.stringify(ticketData),
});
Logger.log(response.getContentText());
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
Assuming I am looking at the right section of the right documentation (https://desk.zoho.com/DeskAPIDocument#Tickets_Createaticket), I think these are your issues:
Server's JSON-encoded response contains no message property, hence Logger.log(result.message); logs undefined. (Maybe trying logging response.getContentText() to see what properties are available in your case -- or refer to the API documentation.)
Authorization and orgId headers are missing in the request you send. (Looks like authtokens are deprecated (https://desk.zoho.com/DeskAPIDocument#Authentication) and you instead need to use OAuth 2.0 (https://desk.zoho.com/DeskAPIDocument#OauthTokens).)
Data needs to be sent in request's body. (You appear to be sending it in the query string.)
I've not read the documentation in detail but I don't see any mention of query string parameters authtoken and JSONString (CTRL+F returns no matches). So you might want to get rid of them in your code and instead follow what the documentation says.
The code below is untested and won't work (as you need to replace with your own credentials). But it should give you an idea of how you can accomplish this.
// See: https://desk.zoho.com/DeskAPIDocument#Tickets#Tickets_Createaticket
// Required: subject, departmentId, contactId
const ticketData = {
subject: location_urgent_inbox_folder_name + ‘ /’ + Name_of_file_to_be_attached, // Taken from your question. Presume these are declared, valid and in scope.
departmentId: '12345', // Replace this with whatever yours is.
contactId: '12345', // Replace this with whatever yours is.
description: 'Ticked via drive',
status: 'open'
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
// See: https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetchurl,-params
const response = UrlFetchApp.fetch(zohoUrl, {
method: 'POST',
contentType: 'application/json',
headers: {
orgId: '12345' // Replace this with whatever yours is.
Authorization: 'Zoho-oauthtoken ....' // See: https://desk.zoho.com/DeskAPIDocument#OauthTokens
},
payload: JSON.stringify(ticketData),
});
Logger.log(response.getContentText());
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
I've never worked with any of Zoho's APIs and haven't worked with Google Apps Script for a while, so apologies if I'm missing something.
Issue resolved,
Posting answer so that it might help someone
//create ticket in zoho
var authtoken = "abcd"; //your_auth_token
var org_id="12345"; //your_organization_id
var department="54321"; // ID of department in which ticket to be raised
var contact="9999"; //ID of customer
var subject="Ticket via google script";
var description="Ticket via google script";
var status="open";
const ticketData = {
subject: subject,
departmentId: department, // Replace this with whatever yours is.
contactId: contact, // Replace this with whatever yours is.
description: description,
status: status
};
const zohoUrl = 'https://desk.zoho.in/api/v1/tickets';
try {
var response = UrlFetchApp.fetch(zohoUrl, {
"method": 'POST',
"muteHttpExceptions": true,
"headers": {
Authorization: authtoken,
orgId: org_id,
contentType: 'application/json',
},
"payload": JSON.stringify(ticketData),
});
const parsed = JSON.parse(response.getContentText());
} catch (error) {
Logger.log(error.toString());
}
We need to call JIRA Rest API to get a specific information from the given query in Dialogflow.
We need to provide response to user based on the response from the API. However, the Dialogflow is unable to retrieve any response from JIRA API through the fulfillment in Firebase Cloud function as it's always timeout.
Based on the log in Firebase console, it always take more than 6000 ms for the execution.
Meanwhile if I use postman to call the JIRA REST API, it takes less than 1 second to get the response.
Some said we need to use promise but I does not seem to work as well.
Please help how should I solve this problem?
Please see my code below
function checkcontract(agent){
var parameters = request.body.queryResult.parameters;
var customer_id = parameters.customer_id;
var bodyData = JSON.stringify({"jql": "project = CDB AND 'Customer ID' ~ "+customer_id,
"maxResults": 1,
"fieldsByKeys": false,
"fields": [
"summary",
"customfield_11949", //Customer ID custom field
"customfield_11937", // Contract Start Date
"customfield_11938", //Contract End Date
"customfield_11936", //email
"customfield_11946", //default JSD request id
"customfield_11943", //project id
"customfield_11941" //project key
],
"startAt": 0
});
var options = {
method: 'POST',
url: '/rest/api/3/search',
auth: { bearer: authorization_token },
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: bodyData
};
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(
'Response: ' + response.statusCode + ' ' + response.statusMessage
);
console.log(body);
});
}
EDIT:
JIRA API returns a response to the function. But the agent.add("message") does not return anything to the chat.
I'm running this little node express server, which is supposed to check if the voucher is valid later and then send an answer back to the client
this is my code
app.post('/voucher', function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
console.log('#### CHECKING VOUCHER ####', results)
let success = {success: true, voucher: {name: results,
xxx: 10}}
success = qs.escape(JSON.stringify(success))
response.end(success)
} )
}
);
It is obviously just an example and the actual check is not implemented yet. So far so good.
Now on the client side where I work with REACT, I can not seem to decode the string I just send there.
there I'm doing this
var voucherchecker = $.post('http://localhost:8080/voucher', code , function(res) {
console.log(res)
let x = JSON.parse(res)
console.log(x)
console.log(qs.unescape(x))
It gives me the error
Uncaught SyntaxError: Unexpected token % in JSON at position 0
When I do it the other way arround
let x = qs.unescape(res)
console.log(x)
console.log(JSON.parse(x))
Than it tells me
Uncaught TypeError: _querystring2.default.unescape is not a function
Maybe you can help me? I don't know what the issue is here. Thank you.
Also another question on this behalf, since I'm only a beginner. Is there smarter ways to do such things than I'm doing it now? I have react which renders on the client and I have a mini express server which interacts a few times with it during the payment process.
The both run on different ports.
What would be the standard way or best practice to do such things?
I'm a bit perplexed as to why your backend code has so much going on in the request.
Since you asked for if there is a different way to write this, I will share with you how I would write it.
Server
It seems that you want your requests to enable CORS, it also seems that you originally wanted to parse a JSON in your request body.
This is how I would recommend you re-write your endpoint
POST /voucher to take a request with body JSON
{
code: "xxxxx"
}
and respond with
{
success: true,
voucher: {
name: results,
xxx: 10
}
}
I would recommend you use express's middleware feature as you will probably use CORS and parse JSON in most your requests so in your project I would.
npm install body-parser
npm install cors
then in your app initialization
var bodyParser = require('body-parser')
var cors = require('cors')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json you can choose to just pars raw text as well
app.use(bodyParser.json())
// this will set Access-Control-Allow-Origin * similar for all response headers
app.use(cors())
You can read more about body-parser and cors in their respective repos, if you don't want to use them I would still recommend you use your own middleware in order to reduse future redundancy in your code.
So far this will substitute this part of your code
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
Now your route definition can just be
app.post('/voucher', function (request, response) {
var result = request.body.code // added by body-parser
console.log('#### CHECKING VOUCHER ####', result)
// express 4+ is smart enough to send this as json
response.status(200).send({
success: true,
voucher: {
name: results,
xxx: 10
}
})
})
Client
your client side can then be, assuming $ is jquery's post function
var body = {
code: code
}
$.post('http://localhost:8080/voucher', body).then(function(res) {
console.log(res)
console.log(res.data)
return res.data
})
I am working on a "Skill" for the new Amazon ECHO. The skill will allow a user to ask Alexa for information on the status and performance of an Enphase solar system. Alexa will respond with results extracted from the JSON based Enphase API. For example, the user could ask,
"Alexa. Ask Enphase how much solar energy I have produced in the last week."
ALEXA <"Your array has produced 152kWh in the last week.">
Problem is it has been years since I've programmed in JavaScript and this is my first time using AWS Lambda. I have not been very successful finding any information on how to embed a JSON query to a third party server within AWS Lambda function. Here is a relevant section of code in my Lambda function:
/**
* Gets power from Enphase API and prepares speach
*/
function GetPowerFromEnphase(intent, session, callback) {
var Power = 0;
var repromptText = null;
var sessionAttributes = {};
var shouldEndSession = false;
var speechOutput = "";
//////////////////////////////////////////////////////////////////////
// Need code here for sending JSON query to Enphase server to get power
// Request:
// https://api.enphaseenergy.com/api/v2/systems/67/summary
// key=5e01e16f7134519e70e02c80ef61b692&user_id=4d7a45774e6a41320a
// Response:
// HTTP/1.1 200 OK
// Content-Type: application/json; charset=utf-8
// Status: 200
// {"system_id":67,"modules":35,"size_w":6270,"current_power":271,
// "energy_today":30030,"energy_lifetime":59847036,
// "summary_date":"2015-03 04","source":"microinverters",
// "status":"normal","operational_at":1201362300,
// "last_report_at":1425517225}
//////////////////////////////////////////////////////////////////////
speechOutput = "Your array is producing " + Power + " kW, goodbye";
shouldEndSession = true;
// Setting repromptText to null signifies that we do not want to reprompt the user.
// If the user does not respond or says something that is not understood, the session
// will end.
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
Some guidance would be much appreciated. Even if someone could point me in the right direction. Thanks!
Request is a very popular library for handling http requests in node.js. Here is an example of a POST using your data:
var request = require('request');
request({
url: 'https://api.enphaseenergy.com/api/v2/systems/67/summary',
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
key: '5e01e16f7134519e70e02c80ef61b692',
user_id: '4d7a45774e6a41320a'
})
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log('BODY: ', body);
var jsonResponse = JSON.parse(body); // turn response into JSON
// do stuff with the response and pass it to the callback...
callback(sessionAttributes,
buildSpeechletResponse(intent.name, speechOutput, repromptText,
shouldEndSession));
}
});
I don't have an example of ECHO/Alexa but here is an example of Lambda calling out to get weather data to send it to Slack