cancel
Showing results for 
Search instead for 
Did you mean: 

Error calling Blockchain Proof of State service from a web app

former_member236392
Participant

Hi guys,

Can you please help me to call an instance of the Proof of State service from my application?

I've been following this guide to build the service. It's up and running and I don't have any problems calling it from the SAP API Hub. Here is the 201 response after I saved a primitive example payload with id "3" below:

{"test": "value"}

Now if I try to generate a JavaScript code snippet and use it in my own application to call the service directly, I receive a 500 error. Here is the code I use:

writeData: function () {
			var data = JSON.stringify({
				"test": "value"
			});
			var xhr = new XMLHttpRequest();
			xhr.withCredentials = false;
			xhr.open("POST", "https://blockchain-service.cfapps.us10.hana.ondemand.com/blockchain/proofOfState/api/v1/states/4");
			xhr.setRequestHeader("Content-Type", "application/json");
			xhr.setRequestHeader("Accept", "application/json");
			xhr.setRequestHeader("Access-Control-Allow-Credentials", "true");
			xhr.setRequestHeader("Access-Control-Allow-Origin", "https://<myRouter>-approuter.cfapps.us10.hana.ondemand.com");
			xhr.setRequestHeader("Access-Control-Allow-Headers", "access-control-allow-origin,authorization,content-type");
            xhr.setRequestHeader("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE");
			xhr.setRequestHeader("Authorization", "Bearer <myToken>");
			
			xhr.onload = function () {
				if (xhr.status === 200) {
					alert("Sucessfully called the API!");
				} else {
					alert("Calling the API failed");
				}
			};
			xhr.send(data);
		}
Here is the 500 response from the service:

{"error":{"code":500,"message":"{\"statusCode\":500} - Please see our documentation at https://help.sap.com/viewer/p/BLOCKCHAIN_APPLICATION_ENABLEMENT/"}}


Mind you, it's not a 403 or a CORS error. I already resolved those. The call does reach the service and I can see it in the dashboard as below:

I don't understand why is it 500? The worst thing that the service doesn't provide explanation and the error is not traceable anywhere. I suspect my payload is not correct, but the documentation doesn't give any examples of a proper payload for a post operation.

So I'd be really grateful if you could suggest anything or give an example of how the service should be called.

Thank you!

------------------------------------------------------

I already looked at the following examples, but couldn't find an answer:
https://developers.sap.com/tutorials/blockchain-application-enablement-proofstate.html
https://help.sap.com/viewer/71a0bb282b2144c6b27fefc772394bff/BLOCKCHAIN/en-US/58cfd045142c4696baced2...
https://github.wdf.sap.corp/blockchain/timestamp/blob/master/index.js

Former Member
0 Kudos

Hi Anton,

were you able to resolve the issue? i don't have an explanation for http 500 errors, but found calling some services directly via curl and from other frontend clients quite finicky. not sure how much SAP would be interested in other products, but it looks like they were trying to troubleshoot this for you.

thx, gm

former_member236392
Participant
0 Kudos

Hi Gregory,

No, I was not able to make it working like I wanted to as I didn't have enough time. Christopher Fries's answer did explain what was going on though. I'll most probably try it once again in the future.

Thanks,
Anton

Accepted Solutions (1)

Accepted Solutions (1)

chris_fries
Advisor
Advisor

Hi Anton,

I’m from the SAP Blockchain Team and inspected your issue. It seems like the problem is caused by the token exchange that is somehow not working correctly.

I saw in your code that you pass the user token to retrieve the refresh_token and then retrieve the technical token for the service via the refresh token (So the technical token is extended with user data). The problem is that the required uaa.user scope seems to get lost. If you call thh blockchain service with that token, it also wants to do a token exchange for the fabric service but fails because the scope is missing. (this caused the 500 error - we will improve the message and status code there).

For now the easiest option for you is to call the service by just using the technical token without doing a token exchange.

Here is a code example:

// get access token
request.post({
    url: baas_options.authentication.url + '/oauth/token?grant_type=client_credentials',
    json: true,
    headers: {
        Authorization: "Basic " + Buffer.from(baas_options.authentication.clientId + ':' + baas_options.authentication.clientSecret, 'utf8')
            .toString('base64')
    }
}, function (err, r, body) {
    // call BAE service
    request.get({
        url: bcService.serviceUrl + '/states/<ID>',
        json: true,
        headers: {
            Authorization: "Bearer " + body.access_token,
        }
    }, function (err, r, body2) {
        // …
    });
});

Best,

Christopher

former_member236392
Participant
0 Kudos

Hi Christopher,

Your code does work as my temporary solution as ideally I would like to see a User who created each transaction in PoS.

Interesting that I see the scope "uaa.resource" in the generated technical token. But that's a separate conversation 🙂

Thanks a lot for you help!

Cheers,
Anton

Answers (3)

Answers (3)

former_member520871
Participant

One question. Are you using Blockchain Enablement Service between your Blockchain Service and the UI5 calls? The call flow must be something like above, where the blockchain service can be anything Multichain, Quorum or Hyperledger.

former_member236392
Participant

Hi Rudramani,

I appreciate you're not giving up on this.

Yes, your picture is exactly my sequence of calls in the application. With a little addition that there is an app router between UI5 and Node.js apps. I've created a Blockchain Application Enablement Service instance under the 'blockchain-proof-of-state' service plan and connected it to Hyperledger.

After I failed calling the service from my Node.js app, I've tried to use the JavaScript code snippet generated by the SAP API Hub to call it directly from UI5 (my first post as part of this question). I failed there too. Tried to call it directly from Postman - that failed as well. Not sure what to do. All of my calls do reach the Blockchain Application Enablement Service instance, but it returns status 500.

I think I'll just try to create a different type of BC AE Service instance and try to play with it. Not sure where my mistake is.

Thanks,
Anton

former_member520871
Participant

Have you tried calling your API via postman?

I will suggest to get your token and with that, call your API via the postman.
Well, I prefer AJAX calls, so I will just provide you my snippet of AJAX.

In the code below, we are calling the API and receiving the token; and then again calling the API with that token and a body. The code mentioned below was written in node.js under MTA UI5.

// update proof history
app.get('/UPDATE_OBJECT_HISTORY', function (req, res, next) {
	var uname = req.query.USERNAME;
	var pass = req.query.PASSWORD;
	var dats = req.query.TIMESTAMP;
	// Get Token
	var tokenoptions = {
		method: 'GET',
		url: configData.tokenUrl,
		qs: {
			grant_type: 'client_credentials'
		},
		headers: {
			'cache-control': 'no-cache',
			Authorization: configData.authorization
		}
	};
	request(tokenoptions, function (error, response, body) {
		if (error) throw new Error(error);
		data = JSON.parse(body);
		token = data.access_token;
		var dataoptions = {
			method: 'PATCH',
			url: configData.blockServUrl + '/logon',
			headers: {
				'cache-control': 'no-cache',
				'Content-Type': 'application/json',
				Accept: 'application/json',
				Authorization: 'Bearer ' + token
			},
// Important in your case
			body: {
				USERNAME: uname,
				PASSWORD: pass,
				TIMESTAMP: dats
			},
			json: true
		};


		request(dataoptions, function (error, response, body) {
			if (error) throw new Error(error);
			res.json(globalBody);
		});
	});
});
former_member236392
Participant
0 Kudos

Hi Rudramani,

Thanks a lot for your code snippet. I'll try it out and let you know.

Thank you,
Anton

former_member236392
Participant
0 Kudos

Hi Rudramani,

No, unfortunately your code snippet didn't help me. I used it in my middleware node.js layer of the MTA app and still received the same generic 500 error without any further explanations. Here is how my code looks like:

var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var cfenv = require('cfenv'); const appEnv = cfenv.getAppEnv();
// below is my hardcoded instance name of the PoS service. It's described as a resource dependency
// to the current node.js module in the mta.yaml var baas_options = appEnv.getServiceCreds("dm2_pos");
var app = express();

app.use(bodyParser.json());
app.use(getUserToken); //app.get("/api/v1/pos/:key", handleRead); app.post("/api/v1/pos/:key", handleWrite);
function handleWrite(req, res) { var dataoptions = { method: 'POST', url: baas_options.serviceUrl + "states/" + req.params.key, headers: { 'cache-control': 'no-cache', 'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer ' + req.user_access_token }, // Important in your case body: { Title: "Title 11", Author: "Author 11" }, json: true }; request(dataoptions, function (err, posRes, body) { //console.log("In the handleWrite callback function. posRes = " + JSON.stringify(posRes)); var status = posRes ? posRes.statusCode : "500"; if (err) { body = err; } res.status(status).send(body); }); }

function getUserToken(req, res, next) { request.post({ url: baas_options.authentication.url + '/oauth/token?client_id=' + baas_options.authentication.clientId + '&response_type=token&grant_type=user_token', headers: { Authorization: req.headers.authorization } }, function (err, res, body) { request.post({ url: baas_options.authentication.url + '/oauth/token?refresh_token=' + JSON.parse(body).refresh_token + '&grant_type=refresh_token', json: true, headers: { Authorization: "Basic " + Buffer.from(baas_options.authentication.clientId + ':' + baas_options.authentication.clientSecret, 'utf8') .toString('base64') } }, function (err, res, body2) { req.user_access_token = body2.access_token; next(); }); }); }


The request successfully reaches the blockchain-proof-of-state service instance. I can see it in the service's 'API Calls' cockpit with status 500, but no further logs available...


Thank you for your help,
Anton

former_member236392
Participant
0 Kudos

Tried to call directly via Postman. Same result 500 without explanation.

POST to https://blockchain-service.cfapps.us10.hana.ondemand.com/blockchain/proofOfState/api/v1/states/15

{
    "error": {
        "code": 500,
        "message": "{\"statusCode\":500} - Please see our documentation at https://help.sap.com/viewer/p/BLOCKCHAIN_APPLICATION_ENABLEMENT/";
    }
}
former_member689201
Discoverer
0 Kudos

Hey I also have a problem with the Proof of State API. I tried to call it from the SAP API Business hub and just got the message: "Unauthorized". I provided all OAuth2.0 informations... Do I need to make some additional configuration to call the api?