mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-17 15:35:09 +00:00
Add patch endpoint
Signed-off-by: James Taylor <jamest@uk.ibm.com>
This commit is contained in:
parent
8250359db6
commit
d810128fcd
2 changed files with 86 additions and 13 deletions
18
README.md
18
README.md
|
|
@ -68,20 +68,14 @@ Update an asset...
|
|||
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
|
||||
```
|
||||
|
||||
Transfer an asset...
|
||||
|
||||
```shell
|
||||
curl --header "Content-Type: application/json" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' 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
|
||||
```
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ export const assetsRouter = express.Router();
|
|||
|
||||
assetsRouter.post(
|
||||
'/',
|
||||
body().isObject().withMessage('body must contain an asset object'),
|
||||
body('id', 'must be a string').notEmpty(),
|
||||
body('color', 'must be a string').notEmpty(),
|
||||
body('size', 'must be a number').isNumeric(),
|
||||
|
|
@ -122,7 +123,7 @@ assetsRouter.options('/:assetId', async (req: Request, res: Response) => {
|
|||
return res
|
||||
.status(OK)
|
||||
.set({
|
||||
Allow: 'DELETE,GET,OPTIONS,PUT',
|
||||
Allow: 'DELETE,GET,OPTIONS,PATCH,PUT',
|
||||
})
|
||||
.json({
|
||||
status: getReasonPhrase(OK),
|
||||
|
|
@ -174,6 +175,7 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => {
|
|||
// TODO this shares a lot of code with the post endpoint!
|
||||
assetsRouter.put(
|
||||
'/:assetId',
|
||||
body().isObject().withMessage('body must contain an asset object'),
|
||||
body('id', 'must be a string').notEmpty(),
|
||||
body('color', 'must be a string').notEmpty(),
|
||||
body('size', 'must be a number').isNumeric(),
|
||||
|
|
@ -261,6 +263,83 @@ assetsRouter.put(
|
|||
}
|
||||
);
|
||||
|
||||
// TODO this shares a lot of code with the post endpoint!
|
||||
assetsRouter.patch(
|
||||
'/:assetId',
|
||||
body()
|
||||
.isArray({
|
||||
min: 1,
|
||||
max: 1,
|
||||
})
|
||||
.withMessage('body must contain an array with a single patch operation'),
|
||||
body('*.op', "operation must be 'replace'").equals('replace'),
|
||||
body('*.path', "path must be '/owner'").equals('/owner'),
|
||||
body('*.value', 'must be a string').isString(),
|
||||
async (req: Request, res: Response) => {
|
||||
logger.debug(req.body, 'Transfer 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(),
|
||||
});
|
||||
}
|
||||
|
||||
const assetId = req.params.assetId;
|
||||
const newOwner = req.body[0].value;
|
||||
|
||||
const contract: Contract = req.app.get('contract');
|
||||
const redis: Redis = req.app.get('redis');
|
||||
const txn = contract.createTransaction('TransferAsset');
|
||||
const txnId = txn.getTransactionId();
|
||||
const txnState = txn.serialize();
|
||||
const txnArgs = JSON.stringify([assetId, newOwner]);
|
||||
|
||||
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(assetId, newOwner);
|
||||
|
||||
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');
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue