mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-22 09:35:10 +00:00
Add delete and put endpoints
Signed-off-by: James Taylor <jamest@uk.ibm.com>
This commit is contained in:
parent
8ebca62b40
commit
8250359db6
2 changed files with 168 additions and 2 deletions
26
README.md
26
README.md
|
|
@ -56,8 +56,32 @@ Create an asset...
|
||||||
curl --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets
|
curl --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets
|
||||||
```
|
```
|
||||||
|
|
||||||
Get an asset...
|
Read an asset...
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -v http://localhost:3000/api/assets/asset7
|
curl -v http://localhost:3000/api/assets/asset7
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Update an asset...
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7
|
||||||
|
```
|
||||||
|
|
||||||
|
Delete an asset...
|
||||||
|
|
||||||
|
```shell
|
||||||
|
curl -v -X DELETE http://localhost:3000/api/assets/asset7
|
||||||
|
```
|
||||||
|
|
||||||
|
Or all of the above for complete chaos!
|
||||||
|
|
||||||
|
```
|
||||||
|
curl --request OPTIONS http://localhost:3000/api/assets/asset7 \
|
||||||
|
--next --header "Content-Type: application/json" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets \
|
||||||
|
--next --request READ http://localhost:3000/api/assets/asset7 \
|
||||||
|
--next --header "Content-Type: application/json" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7 \
|
||||||
|
--next --request READ http://localhost:3000/api/assets/asset7 \
|
||||||
|
--next --request DELETE http://localhost:3000/api/assets/asset7 \
|
||||||
|
--next --request READ http://localhost:3000/api/assets/asset7
|
||||||
|
```
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ assetsRouter.post(
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
return res.status(BAD_REQUEST).json({
|
return res.status(BAD_REQUEST).json({
|
||||||
status: getReasonPhrase(BAD_REQUEST),
|
status: getReasonPhrase(BAD_REQUEST),
|
||||||
|
message: 'Invalid request body',
|
||||||
timestamp: new Date().toISOString(),
|
timestamp: new Date().toISOString(),
|
||||||
errors: errors.array(),
|
errors: errors.array(),
|
||||||
});
|
});
|
||||||
|
|
@ -121,7 +122,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => {
|
||||||
return res
|
return res
|
||||||
.status(OK)
|
.status(OK)
|
||||||
.set({
|
.set({
|
||||||
Allow: 'GET,OPTIONS',
|
Allow: 'DELETE,GET,OPTIONS,PUT',
|
||||||
})
|
})
|
||||||
.json({
|
.json({
|
||||||
status: getReasonPhrase(OK),
|
status: getReasonPhrase(OK),
|
||||||
|
|
@ -169,3 +170,144 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO this shares a lot of code with the post endpoint!
|
||||||
|
assetsRouter.put(
|
||||||
|
'/:assetId',
|
||||||
|
body('id', 'must be a string').notEmpty(),
|
||||||
|
body('color', 'must be a string').notEmpty(),
|
||||||
|
body('size', 'must be a number').isNumeric(),
|
||||||
|
body('owner', 'must be a string').notEmpty(),
|
||||||
|
body('appraisedValue', 'must be a number').isNumeric(),
|
||||||
|
async (req: Request, res: Response) => {
|
||||||
|
logger.debug(req.body, 'Update asset request received');
|
||||||
|
|
||||||
|
const errors = validationResult(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
status: getReasonPhrase(BAD_REQUEST),
|
||||||
|
message: 'Invalid request body',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
errors: errors.array(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req.params.assetId != req.body.id) {
|
||||||
|
return res.status(BAD_REQUEST).json({
|
||||||
|
status: getReasonPhrase(BAD_REQUEST),
|
||||||
|
message: 'Asset IDs must match',
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const contract: Contract = req.app.get('contract');
|
||||||
|
const redis: Redis = req.app.get('redis');
|
||||||
|
const txn = contract.createTransaction('UpdateAsset');
|
||||||
|
const txnId = txn.getTransactionId();
|
||||||
|
const txnState = txn.serialize();
|
||||||
|
const txnArgs = JSON.stringify([
|
||||||
|
req.params.assetId,
|
||||||
|
req.body.color,
|
||||||
|
req.body.size,
|
||||||
|
req.body.owner,
|
||||||
|
req.body.appraisedValue,
|
||||||
|
]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
|
||||||
|
// Store the transaction details and set the event handler in case there
|
||||||
|
// are problems later with commiting the transaction
|
||||||
|
await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp);
|
||||||
|
txn.setEventHandler(createDeferredEventHandler(redis));
|
||||||
|
|
||||||
|
await txn.submit(
|
||||||
|
req.params.assetId,
|
||||||
|
req.body.color,
|
||||||
|
req.body.size,
|
||||||
|
req.body.owner,
|
||||||
|
req.body.appraisedValue
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.status(ACCEPTED).json({
|
||||||
|
status: getReasonPhrase(ACCEPTED),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// TODO will this always catch endorsement errors or can those
|
||||||
|
// arrive later?
|
||||||
|
|
||||||
|
// There's no point retrying a transaction if there were business
|
||||||
|
// logic errors so clear the transaction details
|
||||||
|
//
|
||||||
|
// Note: it would be nice to pick out business logic errors returned
|
||||||
|
// from chaincode, e.g. asset already exists, and return those as a
|
||||||
|
// 400 error with message instead. Unfortunately the asset transfer
|
||||||
|
// sample or Fabric Node SDK do not provide any well defined error
|
||||||
|
// codes that can be checked.
|
||||||
|
await clearTransactionDetails(redis, txnId);
|
||||||
|
|
||||||
|
logger.error(
|
||||||
|
err,
|
||||||
|
'Error processing update asset request for asset ID %s with transaction ID %s',
|
||||||
|
req.params.assetId,
|
||||||
|
txnId
|
||||||
|
);
|
||||||
|
return res.status(INTERNAL_SERVER_ERROR).json({
|
||||||
|
status: getReasonPhrase(INTERNAL_SERVER_ERROR),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
assetsRouter.delete('/:assetId', async (req: Request, res: Response) => {
|
||||||
|
logger.debug(req.body, 'Delete asset request received');
|
||||||
|
|
||||||
|
const contract: Contract = req.app.get('contract');
|
||||||
|
const redis: Redis = req.app.get('redis');
|
||||||
|
const txn = contract.createTransaction('DeleteAsset');
|
||||||
|
const txnId = txn.getTransactionId();
|
||||||
|
const txnState = txn.serialize();
|
||||||
|
const txnArgs = JSON.stringify([req.params.assetId]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
|
||||||
|
// Store the transaction details and set the event handler in case there
|
||||||
|
// are problems later with commiting the transaction
|
||||||
|
await storeTransactionDetails(redis, txnId, txnState, txnArgs, timestamp);
|
||||||
|
txn.setEventHandler(createDeferredEventHandler(redis));
|
||||||
|
|
||||||
|
await txn.submit(req.params.assetId);
|
||||||
|
|
||||||
|
return res.status(ACCEPTED).json({
|
||||||
|
status: getReasonPhrase(ACCEPTED),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// TODO will this always catch endorsement errors or can those
|
||||||
|
// arrive later?
|
||||||
|
|
||||||
|
// There's no point retrying a transaction if there were business
|
||||||
|
// logic errors so clear the transaction details
|
||||||
|
//
|
||||||
|
// Note: it would be nice to pick out business logic errors returned
|
||||||
|
// from chaincode, e.g. asset already exists, and return those as a
|
||||||
|
// 400 error with message instead. Unfortunately the asset transfer
|
||||||
|
// sample or Fabric Node SDK do not provide any well defined error
|
||||||
|
// codes that can be checked.
|
||||||
|
await clearTransactionDetails(redis, txnId);
|
||||||
|
|
||||||
|
logger.error(
|
||||||
|
err,
|
||||||
|
'Error processing delete asset request for asset ID %s with transaction ID %s',
|
||||||
|
req.params.assetId,
|
||||||
|
txnId
|
||||||
|
);
|
||||||
|
return res.status(INTERNAL_SERVER_ERROR).json({
|
||||||
|
status: getReasonPhrase(INTERNAL_SERVER_ERROR),
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue