mirror of
https://github.com/hyperledger/fabric-samples.git
synced 2026-06-23 01:55:10 +00:00
Update the REST Example (#689)
1. The default chaincode use Capitalized JSON Names, whereas for new asset the REST validation didn't.. Adjusted so it matches the chaincode Signed-off-by: Matthew B White <whitemat@uk.ibm.com>
This commit is contained in:
parent
57919f528d
commit
9fa171f824
5 changed files with 68 additions and 67 deletions
|
|
@ -185,7 +185,7 @@ curl --include --header "X-Api-Key: ${SAMPLE_APIKEY}" --request OPTIONS http://l
|
||||||
### Create an asset...
|
### Create an asset...
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"id":"asset7","color":"red","size":42,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets
|
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request POST --data '{"ID":"asset7","Color":"red","Size":42,"Owner":"Jean","AppraisedValue":101}' http://localhost:3000/api/assets
|
||||||
```
|
```
|
||||||
|
|
||||||
The response should include a `jobId` which you can use to check the job status in next step
|
The response should include a `jobId` which you can use to check the job status in next step
|
||||||
|
|
@ -237,13 +237,13 @@ You should see the newly created asset, for example
|
||||||
### Update an asset...
|
### Update an asset...
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"id":"asset7","color":"red","size":11,"owner":"Jean","appraisedValue":101}' http://localhost:3000/api/assets/asset7
|
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PUT --data '{"ID":"asset7","Color":"red","Size":11,"Owner":"Jean","AppraisedValue":101}' http://localhost:3000/api/assets/asset7
|
||||||
```
|
```
|
||||||
|
|
||||||
### Transfer an asset...
|
### Transfer an asset...
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7
|
curl --include --header "Content-Type: application/json" --header "X-Api-Key: ${SAMPLE_APIKEY}" --request PATCH --data '[{"op":"replace","path":"/Owner","value":"Ashleigh"}]' http://localhost:3000/api/assets/asset7
|
||||||
```
|
```
|
||||||
|
|
||||||
### Delete an asset...
|
### Delete an asset...
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,11 @@ content-type: application/json
|
||||||
X-Api-Key: {{api-key}}
|
X-Api-Key: {{api-key}}
|
||||||
|
|
||||||
{
|
{
|
||||||
"id": "asset7",
|
"ID": "asset7",
|
||||||
"color": "red",
|
"Color": "red",
|
||||||
"size": 42,
|
"Size": 42,
|
||||||
"owner": "Jean",
|
"Owner": "Jean",
|
||||||
"appraisedValue": 101
|
"AppraisedValue": 101
|
||||||
}
|
}
|
||||||
|
|
||||||
### Read job status
|
### Read job status
|
||||||
|
|
@ -62,11 +62,11 @@ content-type: application/json
|
||||||
X-Api-Key: {{api-key}}
|
X-Api-Key: {{api-key}}
|
||||||
|
|
||||||
{
|
{
|
||||||
"id": "asset7",
|
"ID": "asset7",
|
||||||
"color": "red",
|
"Color": "red",
|
||||||
"size": 11,
|
"Size": 11,
|
||||||
"owner": "Jean",
|
"Owner": "Jean",
|
||||||
"appraisedValue": 101
|
"AppraisedValue": 101
|
||||||
}
|
}
|
||||||
|
|
||||||
### Transfer asset
|
### Transfer asset
|
||||||
|
|
@ -78,7 +78,7 @@ X-Api-Key: {{api-key}}
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"op": "replace",
|
"op": "replace",
|
||||||
"path": "/owner",
|
"path": "/Owner",
|
||||||
"value": "Ashleigh"
|
"value": "Ashleigh"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -208,11 +208,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.post('/api/assets')
|
.post('/api/assets')
|
||||||
.send({
|
.send({
|
||||||
identifier: 'asset3',
|
wrongidfield: 'asset3',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
|
|
@ -227,7 +227,7 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
{
|
{
|
||||||
location: 'body',
|
location: 'body',
|
||||||
msg: 'must be a string',
|
msg: 'must be a string',
|
||||||
param: 'id',
|
param: 'ID',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
message: 'Invalid request body',
|
message: 'Invalid request body',
|
||||||
|
|
@ -239,11 +239,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.post('/api/assets')
|
.post('/api/assets')
|
||||||
.send({
|
.send({
|
||||||
id: 'asset3',
|
ID: 'asset3',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(202);
|
expect(response.statusCode).toEqual(202);
|
||||||
|
|
@ -401,11 +401,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.put('/api/assets/asset1')
|
.put('/api/assets/asset1')
|
||||||
.send({
|
.send({
|
||||||
id: 'asset3',
|
ID: 'asset3',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'NOTTHERIGHTAPIKEY');
|
.set('X-Api-Key', 'NOTTHERIGHTAPIKEY');
|
||||||
expect(response.statusCode).toEqual(401);
|
expect(response.statusCode).toEqual(401);
|
||||||
|
|
@ -424,11 +424,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.put('/api/assets/asset1')
|
.put('/api/assets/asset1')
|
||||||
.send({
|
.send({
|
||||||
id: 'asset2',
|
ID: 'asset2',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
|
|
@ -448,11 +448,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.put('/api/assets/asset1')
|
.put('/api/assets/asset1')
|
||||||
.send({
|
.send({
|
||||||
identifier: 'asset1',
|
wrongID: 'asset1',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(400);
|
expect(response.statusCode).toEqual(400);
|
||||||
|
|
@ -467,7 +467,7 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
{
|
{
|
||||||
location: 'body',
|
location: 'body',
|
||||||
msg: 'must be a string',
|
msg: 'must be a string',
|
||||||
param: 'id',
|
param: 'ID',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
message: 'Invalid request body',
|
message: 'Invalid request body',
|
||||||
|
|
@ -479,11 +479,11 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.put('/api/assets/asset1')
|
.put('/api/assets/asset1')
|
||||||
.send({
|
.send({
|
||||||
id: 'asset1',
|
ID: 'asset1',
|
||||||
color: 'red',
|
Color: 'red',
|
||||||
size: 5,
|
Size: 5,
|
||||||
owner: 'Brad',
|
Owner: 'Brad',
|
||||||
appraisedValue: 400,
|
AppraisedValue: 400,
|
||||||
})
|
})
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(202);
|
expect(response.statusCode).toEqual(202);
|
||||||
|
|
@ -501,7 +501,7 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
it('PATCH should respond with 401 unauthorized json when an invalid API key is specified', async () => {
|
it('PATCH should respond with 401 unauthorized json when an invalid API key is specified', async () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.patch('/api/assets/asset1')
|
.patch('/api/assets/asset1')
|
||||||
.send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }])
|
.send([{ op: 'replace', path: '/Owner', value: 'Ashleigh' }])
|
||||||
.set('X-Api-Key', 'NOTTHERIGHTAPIKEY');
|
.set('X-Api-Key', 'NOTTHERIGHTAPIKEY');
|
||||||
expect(response.statusCode).toEqual(401);
|
expect(response.statusCode).toEqual(401);
|
||||||
expect(response.header).toHaveProperty(
|
expect(response.header).toHaveProperty(
|
||||||
|
|
@ -531,7 +531,7 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
errors: [
|
errors: [
|
||||||
{
|
{
|
||||||
location: 'body',
|
location: 'body',
|
||||||
msg: "path must be '/owner'",
|
msg: "path must be '/Owner'",
|
||||||
param: '[0].path',
|
param: '[0].path',
|
||||||
value: '/color',
|
value: '/color',
|
||||||
},
|
},
|
||||||
|
|
@ -544,7 +544,7 @@ describe('Asset Transfer Besic REST API', () => {
|
||||||
it('PATCH should respond with 202 accepted json', async () => {
|
it('PATCH should respond with 202 accepted json', async () => {
|
||||||
const response = await request(app)
|
const response = await request(app)
|
||||||
.patch('/api/assets/asset1')
|
.patch('/api/assets/asset1')
|
||||||
.send([{ op: 'replace', path: '/owner', value: 'Ashleigh' }])
|
.send([{ op: 'replace', path: '/Owner', value: 'Ashleigh' }])
|
||||||
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
.set('X-Api-Key', 'ORG1MOCKAPIKEY');
|
||||||
expect(response.statusCode).toEqual(202);
|
expect(response.statusCode).toEqual(202);
|
||||||
expect(response.header).toHaveProperty(
|
expect(response.header).toHaveProperty(
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ export const assetsRouter = express.Router();
|
||||||
|
|
||||||
assetsRouter.get('/', async (req: Request, res: Response) => {
|
assetsRouter.get('/', async (req: Request, res: Response) => {
|
||||||
logger.debug('Get all assets request received');
|
logger.debug('Get all assets request received');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mspId = req.user as string;
|
const mspId = req.user as string;
|
||||||
const contract = req.app.locals[mspId]?.assetContract as Contract;
|
const contract = req.app.locals[mspId]?.assetContract as Contract;
|
||||||
|
|
@ -59,11 +58,11 @@ assetsRouter.get('/', async (req: Request, res: Response) => {
|
||||||
assetsRouter.post(
|
assetsRouter.post(
|
||||||
'/',
|
'/',
|
||||||
body().isObject().withMessage('body must contain an asset object'),
|
body().isObject().withMessage('body must contain an asset object'),
|
||||||
body('id', 'must be a string').notEmpty(),
|
body('ID', 'must be a string').notEmpty(),
|
||||||
body('color', 'must be a string').notEmpty(),
|
body('Color', 'must be a string').notEmpty(),
|
||||||
body('size', 'must be a number').isNumeric(),
|
body('Size', 'must be a number').isNumeric(),
|
||||||
body('owner', 'must be a string').notEmpty(),
|
body('Owner', 'must be a string').notEmpty(),
|
||||||
body('appraisedValue', 'must be a number').isNumeric(),
|
body('AppraisedValue', 'must be a number').isNumeric(),
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
logger.debug(req.body, 'Create asset request received');
|
logger.debug(req.body, 'Create asset request received');
|
||||||
|
|
||||||
|
|
@ -79,7 +78,7 @@ assetsRouter.post(
|
||||||
}
|
}
|
||||||
|
|
||||||
const mspId = req.user as string;
|
const mspId = req.user as string;
|
||||||
const assetId = req.body.id;
|
const assetId = req.body.ID;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const submitQueue = req.app.locals.jobq as Queue;
|
const submitQueue = req.app.locals.jobq as Queue;
|
||||||
|
|
@ -88,10 +87,10 @@ assetsRouter.post(
|
||||||
mspId,
|
mspId,
|
||||||
'CreateAsset',
|
'CreateAsset',
|
||||||
assetId,
|
assetId,
|
||||||
req.body.color,
|
req.body.Color,
|
||||||
req.body.size,
|
req.body.Size,
|
||||||
req.body.owner,
|
req.body.Owner,
|
||||||
req.body.appraisedValue
|
req.body.AppraisedValue
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(ACCEPTED).json({
|
return res.status(ACCEPTED).json({
|
||||||
|
|
@ -190,11 +189,11 @@ assetsRouter.get('/:assetId', async (req: Request, res: Response) => {
|
||||||
assetsRouter.put(
|
assetsRouter.put(
|
||||||
'/:assetId',
|
'/:assetId',
|
||||||
body().isObject().withMessage('body must contain an asset object'),
|
body().isObject().withMessage('body must contain an asset object'),
|
||||||
body('id', 'must be a string').notEmpty(),
|
body('ID', 'must be a string').notEmpty(),
|
||||||
body('color', 'must be a string').notEmpty(),
|
body('Color', 'must be a string').notEmpty(),
|
||||||
body('size', 'must be a number').isNumeric(),
|
body('Size', 'must be a number').isNumeric(),
|
||||||
body('owner', 'must be a string').notEmpty(),
|
body('Owner', 'must be a string').notEmpty(),
|
||||||
body('appraisedValue', 'must be a number').isNumeric(),
|
body('AppraisedValue', 'must be a number').isNumeric(),
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
logger.debug(req.body, 'Update asset request received');
|
logger.debug(req.body, 'Update asset request received');
|
||||||
|
|
||||||
|
|
@ -209,7 +208,7 @@ assetsRouter.put(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.params.assetId != req.body.id) {
|
if (req.params.assetId != req.body.ID) {
|
||||||
return res.status(BAD_REQUEST).json({
|
return res.status(BAD_REQUEST).json({
|
||||||
status: getReasonPhrase(BAD_REQUEST),
|
status: getReasonPhrase(BAD_REQUEST),
|
||||||
reason: 'ASSET_ID_MISMATCH',
|
reason: 'ASSET_ID_MISMATCH',
|
||||||
|
|
@ -263,7 +262,7 @@ assetsRouter.patch(
|
||||||
})
|
})
|
||||||
.withMessage('body must contain an array with a single patch operation'),
|
.withMessage('body must contain an array with a single patch operation'),
|
||||||
body('*.op', "operation must be 'replace'").equals('replace'),
|
body('*.op', "operation must be 'replace'").equals('replace'),
|
||||||
body('*.path', "path must be '/owner'").equals('/owner'),
|
body('*.path', "path must be '/Owner'").equals('/Owner'),
|
||||||
body('*.value', 'must be a string').isString(),
|
body('*.value', 'must be a string').isString(),
|
||||||
async (req: Request, res: Response) => {
|
async (req: Request, res: Response) => {
|
||||||
logger.debug(req.body, 'Transfer asset request received');
|
logger.debug(req.body, 'Transfer asset request received');
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,8 @@ const { BAD_REQUEST, INTERNAL_SERVER_ERROR, NOT_FOUND } = StatusCodes;
|
||||||
export const createServer = async (): Promise<Application> => {
|
export const createServer = async (): Promise<Application> => {
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
|
// Remember for production usage, to check any TLS or CORS requirements
|
||||||
|
|
||||||
app.use(
|
app.use(
|
||||||
pinoMiddleware({
|
pinoMiddleware({
|
||||||
logger,
|
logger,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue