Submitting a transaction via RESTful API (how to handle transactionid and timestamp)

rest atomic transaction
transactions in web api
transaction in web api c#
rollback api calls
rest api
atomic distributed transactions: a restful design
spring transaction rest service
c# web api transactionscope

Problem: I am unable to POST a transaction via the RESTful API generated by the composer-rest-server. I am receiving statusCode 422; the transaction instance is not valid. However, the same example works in the Playground.

Scenario: I've set up a transaction called Offer in my .cto file which posts an offer to buy a house:

// Offer - Specifies an offer that a bidder places on a house listing with an associated price

transaction Offer {
  o Double bidPrice
  --> HouseListing listing
  --> Person bidder
}

The composer-rest-server has generated an API with the following JSON string to post a transaction of type Offer:

{
  "$class": "org.acme.purchasing.Offer",
  "bidPrice": 0,
  "listing": "string",
  "bidder": "string",
  "transactionId": "string",
  "timestamp": "2017-07-21T13:37:09.460Z"
}

I've since replaced this with a sample transaction using the following JSON code derived from the above example:

{
  "$class": "org.acme.purchasing.Offer",
  "bidPrice": 1000,
  "listing": "001",
  "bidder": "RJOHNSON",
  "transactionId": "1b9aa63c-dfad-4aad-a610-dfc80f2796b2",
  "timestamp": "2017-07-21T13:37:09.460Z"
}

The response returned is error code 422:

{
  "error": {
    "statusCode": 422,
    "name": "ValidationError",
    "message": "The `Offer` instance is not valid. Details: `transactionId` can't be set (value: \"1b9aa63c-dfad-4aad-a610-d...6b2\").",
    "details": {
      "context": "Offer",
      "codes": {
        "transactionId": [
          "absence"
        ]
      },
      "messages": {
        "transactionId": [
          "can't be set"
        ]
      }
    },
    "stack": "ValidationError: The `Offer` instance is not valid. Details: `transactionId` can't be set (value: \"1b9aa63c-dfad-4aad-a610-d...6b2\").\n    at /usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/dao.js:355:12\n    at ModelConstructor.<anonymous> (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/validations.js:566:11)\n    at ModelConstructor.next (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/hooks.js:93:12)\n    at ModelConstructor.<anonymous> (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/validations.js:563:23)\n    at ModelConstructor.trigger (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/hooks.js:83:12)\n    at ModelConstructor.Validatable.isValid (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/validations.js:529:8)\n    at /usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/dao.js:351:9\n    at doNotify (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:155:49)\n    at doNotify (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:155:49)\n    at doNotify (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:155:49)\n    at doNotify (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:155:49)\n    at Function.ObserverMixin._notifyBaseObservers (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:178:5)\n    at Function.ObserverMixin.notifyObserversOf (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:153:8)\n    at Function.ObserverMixin._notifyBaseObservers (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:176:15)\n    at Function.ObserverMixin.notifyObserversOf (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:153:8)\n    at Function.ObserverMixin._notifyBaseObservers (/usr/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/observer.js:176:15)"
  }
}

Now the strange thing is that I've deployed the same BNA onto the Hyperledger Composer Playground and am able to execute transactions of type Offer successfully.

Note that in the Playground, "transactionId" and "timestamp" are not specified as the Playground appears to take care of these values. For example, this is what Playground proposes to me initially:

{
  "$class": "org.acme.purchasing.Offer",
  "bidPrice": 0,
  "listing": "resource:org.acme.purchasing.HouseListing#id:7965",
  "bidder": "resource:org.acme.purchasing.Person#id:4441"
}

Can anyone advise why it's saying the Offer instance is not valid? My first thought was that it's not liking the string I'm placing in "transactionId" but another Stack Overflow post points out that the transactionId is just an arbitrary UUIDv4 string which I've generated already.

Update #1: Failing even with default demo

In order to ensure by BNA is error-free, I've deployed the default carauction-demo (resembles my example closely) onto my local Hyperledger Fabric instance and deployed the composer-rest-server. I've also deployed the same BNA into the Playground. All assets and participants were created identical in both from the Explorer (local instance) and Playground. When it comes time to submit an Offer transaction:

{
  "$class": "org.acme.vehicle.auction.Offer",
  "bidPrice": 800,
  "listing": "resource:org.acme.vehicle.auction.VehicleListing#L001",
  "member": "resource:org.acme.vehicle.auction.Member#member3@acme.org"
}

This JSON was generated by the Playground and succeeds there. Copy/paste/executing into the Explorer yields a status 500 error.

{
  "error": {
    "statusCode": 500,
    "name": "Error",
    "message": "error trying invoke chaincode. Error: chaincode error (status: 500, message: Error: Object with ID 'string' in collection with ID 'Asset:org.acme.vehicle.auction.VehicleListing' does not exist)",
    "stack": "Error: error trying invoke chaincode. Error: chaincode error (status: 500, message: Error: Object with ID 'string' in collection with ID 'Asset:org.acme.vehicle.auction.VehicleListing' does not exist)\n    at _initializeChannel.then.then.then.then.catch (/usr/lib/node_modules/composer-rest-server/node_modules/composer-connector-hlfv1/lib/hlfconnection.js:806:34)"
  }
}

I'm still at a lost as to what is wrong here.

After much experimentation and some searching, I've concluded that the problem was that NPM was installed using sudo (as root). I redid the installation as non-root and the problem has now been solved. Everything is working as expected.

Submitting a transaction via RESTful API (how to handle - html, Submitting a transaction via RESTful API (how to handle transactionid and timestamp). rest atomic transaction spring rest transactions rest api transaction in web  The service responds with a transaction id in the Location response header. Use the transaction id to control the transaction in which MarkLogic Server evaluates future requests; see Associating a Transaction with a Request. The transaction id returned in the Location header is of the form.

Composer updates the transactionId itself as its generated, you cannot do this in your JSON and hence why you get the error. This is a Loopback -> Swagger conversion issue as it should not appear in a /POST REST operation - captured here https://github.com/hyperledger/composer/issues/663

Managing Transactions (REST Application Developer's Guide , Submitting a transaction via RESTful API (how to handle transactionid and timestamp) - hyperledger. This standard allows using the application server as a transaction coordinator with a specific REST API for creating and joining the distributed transactions. The RESTful web services that wish to participate in the two-phase transaction also have to support a specific REST API.

So I have successfully executed Offer transactions (/POST). I think the '500' error is because there is a missing field ('string' type), or relationship in your Offer transaction via REST.

Using the example of the Car Auction network https://github.com/hyperledger/composer-sample-networks/blob/master/packages/carauction-network/models/auction.cto

Either of these Offer transactions using /POST were successful in Explorer:

{
  "$class": "org.acme.vehicle.auction.Offer",
  "bidPrice": 20,
  "listing": "org.acme.vehicle.auction.VehicleListing#100",
  "member": "org.acme.vehicle.auction.Member#a@b.com"
 }

OR

{
  "$class": "org.acme.vehicle.auction.Offer",
  "bidPrice": 20,
  "listing": "org.acme.vehicle.auction.VehicleListing#100",
  "member": "org.acme.vehicle.auction.Member#a@b.com",
  "timestamp": "2017-07-28T14:07:02.558Z"
}

responded with a 200 (SUCCESS) and a transactionId in Explorer:

{
  "$class": "org.acme.vehicle.auction.Offer",
  "bidPrice": 20,
  "listing": "org.acme.vehicle.auction.VehicleListing#100",
  "member": "org.acme.vehicle.auction.Member#a@b.com",
  "transactionId": "e75b9934-1f08-4daf-90db-702bbe4b8fa1"
}

This is my VehicleListing asset JSON for #100 above

{
  "$class": "org.acme.vehicle.auction.VehicleListing",
  "listingId": "100",
  "reservePrice": 50,
  "description": "string",
  "state": "FOR_SALE",
  "offers": [
    {
      "$class": "org.acme.vehicle.auction.Offer",
      "bidPrice": 50,
      "listing": "100",
      "member": "resource:org.acme.vehicle.auction.Member#a@b.com",
      "transactionId": "string123",
      "timestamp": "2017-07-28T14:07:02.825Z"
    }
  ],
  "vehicle": "resource:org.acme.vehicle.auction.Vehicle#123"
}

And I created asset for Vehicle 123 as well as Member a@b.com

Core API, The REST Client API provides transaction control through the /transactions service and a Commit or rollback the transaction by sending a POST request to the /transactions service. Use the transaction id to control the transaction in which MarkLogic Server <rapi:transaction-timestamp>0</rapi:transaction-​timestamp>  RESTful API often use GET (read), POST (create), PUT (replace/update) and DELETE (to delete a record). Not all of these are valid choices for every single resource collection, user, or action. Make sure the incoming HTTP method is valid for the session token/API key and associated resource collection, action, and record.

Account and Transaction API Specification, CLI; REST API; Node.js Application; Using Swagger JS Plugin; Marbles Currently, the build will create a peer executable file). chaincode invoke, The transaction ID (UUID) Timestamp timestamp = 2; repeated Transaction transactions = 3; bytes Use the Registrar APIs to manage end user registration with the CA. RESTful API Authentication Basics We could all use a refresher on API authentication basics. In this post, Guy Levin provides just that, including how to achieve authentication.

API Documentation / RESTful API / CardGate protocol, This specification describes the Account Information and Transaction The API adheres to RESTful API concepts where possible and The unique id of the ASPSP to which the request is issued. or not-present is identified via the x-fapi-​customer-ip-address header. Handling Expired Access Tokens. Submit a new sale transaction or an authorization and delayed capture transaction of $34 for the rest of the shipment. When you ship the remainder of the product, you can collect the remaining $34 in a sale transaction that uses the initial authorization as a reference transaction.

Hyperledger Composer Historian, All transactions with the same ref will have the same transaction ID. info, s 255, Optional extra information that was submitted to the gateway for this transaction. loop do DB.transaction do # pull jobs in large batches job_batch = StagedJobs.order('id').limit(1000) if job_batch.count > 0 # insert each one into the real job queue job_batch.each do |job| Sidekiq.enqueue(job.job_name, *job.job_args) end # and in the same transaction remove these records StagedJobs.where('id <= ?', job_batch.last).delete end end end

Comments
  • did you only reinstall the npm or did you have to reinstall the whole hyperledger fabric?
  • Thanks and appreciate the assistance. Once I've removed the transactionId string, I get an error statusCode 500, "error trying invoke chaincode. Error: chaincode error (status: 500, message: Error: Object with ID 'string' in collection with ID 'Asset:org.acme.purchasing.HouseListing' does not exist)". It seems like it's still expecting a string object.
  • Sounds like its trying to update an asset that hasn't either been specified properly eg fully qualified or the id for which doesn't exist? I see that listing (in the transaction) has a relationship to Asset HouseListing defined (but not posted here) earlier..and for which you've still got instance(s) presumably.
  • Yes, the instance for that asset is still currently in place. As a test, I've deployed the default carauction-network BNA to my hyperledger instance and executed composer-rest-server. Again, deploying this BNA to the Playground, I was able to successfully create assets, participants and execute Offer transactions. When I try to perform the same via the RESTful API Explorer, I can create assets and participants, but fails when attempting to execute Offer transactions (error status 500). Has anyone executed an Offer transaction on carauction-network via the Explorer or is it a bug?
  • Thanks again for your help on this and I too, was able to successfully execute the transactions now. It turned out to be npm being installed with root. Once I installed npm under my own username, everything was okay. There must've been an access issue, but my issue has now been resolved!