Hyperledger composer calling external REST API - hyperledger

I am a developer with hyperledger composer. I try to use Calling an HTTP or REST API from Transaction Processor Functions with method POST and request body but I have error status code 500. I want to use method POST with request body to my server.
My code:
async function testStocks(transaction) {
const participant = getCurrentParticipant();
const json = '{"name:tester"}';//my request body
await request.post({ uri: 'http://www...', json });
// Update the current participant in the participant registry.
const participantRegistry = await getParticipantRegistry('org.example.Trader');
await participantRegistry.update(participant);
}
My error:
{
"error": {
"statusCode": 500,
"name": "Error",
"message": "Error trying invoke business network. Error: No valid responses from any peers.\nResponse from attempted peer comms was an error: Error: 2 UNKNOWN: error executing chaincode: transaction returned with failure: StatusCodeError: 400 - undefined",
"stack": "Error: Error trying invoke business network. Error: No valid responses from any peers.\nResponse from attempted peer comms was an error: Error: 2 UNKNOWN: error executing chaincode: transaction returned with failure: StatusCodeError: 400 - undefined\n at _initializeChannel.then.then.then.then.catch (/home/pc/.nvm/versions/node/v8.10.0/lib/node_modules/composer-rest-server/node_modules/composer-connector-hlfv1/lib/hlfconnection.js:965:34)\n at <anonymous>"
}
}

participant variable is undefined in await participantRegistry.update(participant);.
You are missing code from the example # https://hyperledger.github.io/composer/latest/integrating/call-out.
// Get the current participant, and update their stock and balance.
const participant = getCurrentParticipant();
// update participant here... <<--------------------
// Update the current participant in the participant registry.
const participantRegistry = await getParticipantRegistry('org.example.Trader');
await participantRegistry.update(participant);

Related

cannot call cloud function

in my project I use some cloud functions: one of them sets custom claims, it works properly, I have a second function that when fired should write some data on the realtime Db,but once is fired I get a CORS Error; this is the faulty function:
exports.insertUser = functions.https.onCall((data)=>{
const db = admin.database();
const reference = "userProfile";
return db.ref(reference).push(data.user).then(()=>{
return {message: "utente inserito"};
}).catch((error)=>{
return error;
})
});
this is the error that I get:
Access to fetch at 'https://us-central1-trasportostudenti-
bc19c.cloudfunctions.net/insertUser' from origin 'http://localhost:8100' has been blocked by CORS policy: Response to preflight request doesn't pass access control check
firebase's log states that the problem is in my code; any suggestions to fix this error?

Ballerina Oauth2 authenticated endpoint returning a 406

I am trying to call a 3rd party service that uses Oauth2 Password Credentials to get an authentication token. Ballerina is returning the following messages.
2020-04-23 15:07:35,414 ERROR [ballerina/oauth2] - Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}}
2020-04-23 15:07:35,418 ERROR [ballerina/oauth2] - Failed to generate OAuth2 token. : error {ballerina/oauth2}Error message=Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}}
error {ballerina/http}AuthenticationFailed message=Failed to prepare request at bearer auth handler. cause=error {ballerina/auth}Error message=Failed to generate OAuth2 token. cause=error {ballerina/oauth2}Error message=Received an invalid response with status-code: 406; and payload: {"fault":{"faultstring":"Raising fault. Fault name : RF.Raise-406-Exception","detail":{"errorcode":"steps.raisefault.RaiseFault"}}}
It's the 406 code that is confusing me as I have set both the content type & accept headers to "application/json" which is what the service requires.
However, the second message says "Failed to generate OAuth2 token" so could it be the call to get the oauth token that is returning the 406? If so how do I set the accept header on the token service call?
Using Ballerina I have called the token endpoint and successfully got a token but if I try to call a service using a PasswordGrantConfig those are the errors I get. I've tried everything I can think of and have successfully got other services using ClientCredentialsGrantConfig to work.
Any help gratefully received.
The relevant code is below. The three sections below are parts of the code in 3 different .bal files.
// configure the Oauth2 Config
import ballerina/config;
import ballerina/http;
import ballerina/oauth2;
public function getOauth2Handler() returns http:BearerAuthHandler {
oauth2:PasswordGrantConfig passwordGrantConfig = {
tokenUrl: config:getAsString("experian.authentication.tokenUrl"),
username: config:getAsString("experian.authentication.username"),
password: config:getAsString("experian.authentication.password"),
clientId: config:getAsString("experian.authentication.clientId"),
clientSecret: config:getAsString("experian.authentication.clientSecret"),
credentialBearer: http:AUTH_HEADER_BEARER
};
oauth2:OutboundOAuth2Provider oauth2Provider = new (passwordGrantConfig);
return new (oauth2Provider);
}
// Configure the API Client
http:ClientConfiguration delphiSelectClientConfig = {
auth: {
authHandler: experian:getOauth2Handler()
}
};
experian:DelphiSelectClientConfig delphiSelectConfig = {
serviceUrl: config:getAsString("experian.services.delphi-select.serviceUrl"),
clientConfig: delphiSelectClientConfig
};
experian:DelphiSelectClient delphiSelectClient = new (delphiSelectConfig);
// Call the endpoint using the Oath2 configuration
import ballerina/http;
import ballerina/io;
public type DelphiSelectClientConfig record {
string serviceUrl;
http:ClientConfiguration clientConfig;
};
//==============================
//============Client============
//==============================
public type DelphiSelectClient client object {
public http:Client clientEp;
public http:ClientConfiguration config;
public function __init(DelphiSelectClientConfig config) {
http:Client httpEp = new (config.serviceUrl, {auth: config.clientConfig.auth});
self.clientEp = httpEp;
self.config = config.clientConfig;
}
public remote function newApplication() returns #untainted json|error {
io:println("In newApplication function");
http:Request request = new;
json requestBody = newApplicationBody; // get test data from json in another file
request.setJsonPayload(requestBody);
var response = check self.clientEp->post("/application", request);
var payload = check response.getJsonPayload();
return payload;
}
};
I have also modified my test code to call the token EP and deliberately set accept to an unacceptable value, for example, "text/csv". In this case I get the same error response. However setting accept to "*/*" does work. Final test; accept of "" (empty) also fails so I suspect that the BearerAuthHandler is not setting any value for accept.
So can I force the BearerAuthHandler to set an accept of "application/json"?
Thanks.
See picture below.
Also, the example in the Oath2 spec you referenced shows a content-type value being set. Even a value of “*/*” would work but I suspect Ballerina leaves it blank.
I have raised the GitHub issue Need to be able to set http header values for OutboundOAuth2Provider
The main objective of http:OutboundAuthHandler objects are to prepare the http:Request with authentication information that needs to be authenticated with external endpoint you are calling to.
The http:BearerAuthHandler is responsible for adding Authorization header with the value of Bearer <token>. "token" is prepared with the provided information. So, there is no option to force http:BearerAuthHandler to set any header for the request.
But in this case, if the API successfully respond if there is Accept header with the value of application/json, you can simply add that header to the http:Request before calling the POST request as follow:
request.addHeader("Accept", "application/json");

How to create SendBird user with SendBird Platform API and Request node library

We are building a react-native chat app. We are implementing a back end authentication solution on google Firebase. The creation of a new user in Firebase Auth triggers a cloud function which should create a new SendBird user with an access token. The access token will be stored in Cloud Firestore, ready for retrieval the next time the user logs in.
We are having trouble implementing the POST request that creates the new user via the platform API. We are using the Request library for node.js. We are able to reach the API endpoint, but the following object is returned: { message: 'SendBird API Endpoint.', error: true }. There is no indication of what the error may be.
This happens when sending the request to the base url. When we send the request to /users or /v3/users, we receive a 403 error.
Any indication as to what may be causing this problem would be greatly appreciated.
Below is the cloud function index.js code
const functions = require('firebase-functions');
const admin = require("firebase-admin");
const request = require('request');
admin.initializeApp();
exports.handleNewUser = functions.auth.user().onCreate((user) => {
var newUserRequestBody = {
"user_id": user.email,
"nickname": user.email,
"profile_url": "",
"issue_access_token": true,
}
request.post({
headers: {
'Content-Type': 'application/json, charset=utf8',
'Api-Token': // API Token
},
url: 'https://api-{application_id}.sendbird.com',
form: newUserRequestBody
}, function(error, response, body){
if (!error && response.statusCode === 200) {
const info = JSON.parse(body);
console.log("request successful");
console.log(response.statusCode);
console.log(info);
}
else{
console.log("request unsuccessful");
console.log(response.statusCode);
console.log(error);
}
});
return null;
});
Did you try with full path of end point to url: (including /v3/users)?
Or you may need to use "baseUrl" like below?
https://github.com/request/request#requestoptions-callback
Also, you need to make sure that you correctly used {application_id} value and {API Token} value.
You can double check this from your dashboard of SendBird.
http://dashboard.sendbird.com > Log in with your ID > select your APP.
There is a section named "App credentials" in "Overview" menu.
You can double check your API-request URL and API-Token value from there.

Method for invoking transaction from another transaction in Hyperledge composer

The old version of hyperledger support below method. But newest not
const generateReport = getFactory().newTransaction('org.cusat.hospital', 'GenerateReport');
While testing in new version shows an error of
Error: No valid responses from any peers. Response from attempted peer comms was an error: Error: transaction returned with failure: TypeError: getFactory(...).newTransaction is not a function
Please suggest alternative method.
i found one way of invoking transaction from java script. see if this helps.
const TransactionSubmit = require('composer-cli').Transaction.Submit;
let options = {
card: 'admin#tutorial-network',
data: '{"$class":"net.biz.digitalPropertyNetwork.RegisterPropertyForSale","transactionId":"TRANSACTION_001","seller":"mae#biznet.org","title":"TITLE_001"}'
};
TransactionSubmit.handler(options);

Cypress visit and wait timeouts ignored

I created a test where I setup a route, try to visit a page which makes an API request to the route and then wait for the route response:
cy
.server()
.route('GET', '/api/testing')
.as('testing');
cy.visit('/index.html', { timeout: 60000 });
cy.wait('#testing', { timeout: 60000 });
This only waits for the Cypress global default responseTimeout of 30 seconds and then fails the API request.
Here's the error message logged by Cypress in the console:
Cypress errored attempting to make an http request to this url:
https://localhost:4200/api/testing
The error was:
ESOCKETTIMEDOUT
The stack trace was:
Error: ESOCKETTIMEDOUT
at ClientRequest. (…\node_modules\cypress\dist\Cypress\resources\app\packages\server\node_modules\request\request.js:778:19)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at ClientRequest.emit (events.js:207:7)
at TLSSocket.emitTimeout (_http_client.js:722:34)
at Object.onceWrapper (events.js:314:30)
at emitNone (events.js:105:13)
at TLSSocket.emit (events.js:207:7)
at TLSSocket.Socket._onTimeout (net.js:402:8)
at ontimeout (timers.js:469:11)
at tryOnTimeout (timers.js:304:5)
at Timer.listOnTimeout (timers.js:264:5)
Adding a responseTimeout to the global config of Cypress will increase the timeout, but why isn't the timeout for either the visit or the wait occurring?
See the code example on this page commands - wait - Alias
// Wait for the route aliased as 'getAccount' to respond
// without changing or stubbing its response
cy.server()
cy.route('/accounts/*').as('getAccount')
cy.visit('/accounts/123')
cy.wait('#getAccount').then((xhr) => {
// we can now access the low level xhr
// that contains the request body,
// response body, status, etc
})
I would add the then((xhr) => to your code and see what response is coming through.
Logic says that if a bogus route waits the full timeout, but a 'failed legitimate route' does not, then a response with failure code is being sent back from the server within the timeout period.
The block of code in request.js where the error comes from has an interesting comment.
self.req.on('socket', function(socket) {
var setReqTimeout = function() {
// This timeout sets the amount of time to wait *between* bytes sent
// from the server once connected.
//
// In particular, it's useful for erroring if the server fails to send
// data halfway through streaming a response.
self.req.setTimeout(timeout, function () {
if (self.req) {
self.abort()
var e = new Error('ESOCKETTIMEDOUT') <-- LINE 778 REFERENCED IN MESSAGE
e.code = 'ESOCKETTIMEDOUT'
e.connect = false
self.emit('error', e)
}
})
}
This may be a condition you want to test for (i.e connection broken mid-response).
Unfortunately, there seems to be no syntax cy.wait().catch(), see Commands-Are-Not-Promises
You cannot add a .catch error handler to a failed command.
You may want to try stubbing the route instead of setting the breakpoint on the server, but I'm not sure what form the fake response should take. (Ref route with stubbing)
.vist() and .wait() didn't work for me, error logs on cypress suggested using .request() instead which works fine.
cy.server();
cy.request('/api/path').then((xhr) => {
console.log(xhr.body)
})

Resources