Skip to content
This repository has been archived by the owner on Mar 8, 2020. It is now read-only.

Commit

Permalink
Add REST Server support for returning transactions (#4291)
Browse files Browse the repository at this point in the history
* Create APIKEY support to composer-rest-server

Signed-off-by: Nicola Paoli <[email protected]>

* [APIKEY] Add control for APIKEY when processing requests to the REST API

* [APIKEY] Add flag to specifiy APIKEY when starting composer-rest-server via cmd or env Var COMPOSER_APIKEY

* [APIKEY] Add Unit Test to access the REST API using an APIKEY

* [APIKEY] Add Documentation for using the APIKEY to access the REST API

* [APIKEY] Small fix on text

* [APIKEY_FIX] Typo corrections for 'API key'
Signed-off-by: Nicola Paoli <[email protected]>

* [APIKEY_FIX] Removing Authentication from API Key Unit Test
Signed-off-by: Nicola Paoli <[email protected]>

* Small fix for readability
Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add support for transactions with @returns functionality

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add testing for transactions with @returns functionality

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add support for transactions with @returns functionality

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Fix eslint on discover returning transactions

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add support for @returns transactions to REST Server

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Test @returns transactions support to REST Server

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add support for transactions @returns Concepts array

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add unit test coverage for transaction with @returns functionality

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Add unit test coverage when returning an array of concepts

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Remove customised route for returning transactions

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Fix method descriptions

Signed-off-by: Nicola Paoli <[email protected]>

* [#4245]: Remove console statement on returning transactions

Signed-off-by: Nicola Paoli <[email protected]>
  • Loading branch information
nicolapaoli authored and Simon Stone committed Aug 1, 2018
1 parent 98f6856 commit d3d7794
Show file tree
Hide file tree
Showing 9 changed files with 1,547 additions and 11 deletions.
100 changes: 100 additions & 0 deletions packages/composer-rest-server/server/boot/composer-discovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,103 @@ function registerQueryMethods(app, dataSource, namespaces) {
});
}

/**
* to register each composer named transaction method as a POST method on the REST API
* @param {Object} app The LoopBack application.
* @param {Object} dataSource The LoopBack data source.
* @param {Object} Transaction The LoopBack Transaction model
* @param {Object} connector The LoopBack connector.
* @param {Transaction} transaction the named Composer transaction to register
*/
function registerReturningTransactionMethod(app, dataSource, Transaction, connector, transaction) {

console.log('Registering returning transaction: ' + transaction.name);

let returnType;
if (transaction.decorators.returns.isArray) {
returnType = [transaction.decorators.returns.schema];
} else {
returnType = transaction.decorators.returns.schema;
}

// Apply any required updates to the specified model schema.
transaction.transactionSchema = updateModelSchema(transaction.transactionSchema);

// Create and register the models.
const TransactionSchema = app.loopback.createModel(transaction.transactionSchema);

restrictModelMethods(transaction.transactionSchema, TransactionSchema);

// Now we register the model against the data source.
app.model(TransactionSchema, {
dataSource: dataSource,
public: true
});

// Create the transactionMethod
TransactionSchema.create = (data, options, callback) => {
connector.create(transaction.name, data, options, callback);
};

// Create the remotheMethod for the transaction
TransactionSchema.remoteMethod(
'create', {
description: 'Execute returning transaction ' + transaction.name,
accepts: [{
arg: 'data',
type: transaction.name,
required: true,
http: {
source: 'body'
}
}, {
arg: 'options',
type: 'object',
http: 'optionsFromRequest'
}],
returns: {
type : returnType,
root: true
},
http: {
verb: 'post',
path: '/'
}
}
);
}

/**
* Register the composer methods for returning transactions on the REST API
* @param {Object} app The LoopBack application.
* @param {Object} dataSource The LoopBack data source.
* @param {Object[]} modelDefinitions An array of model definitions.
* @returns {Promise} a promise when complete
*/
function registerReturningTransactionMethods(app, dataSource) {

console.log('Discovering the Returning Transactions..');
// Grab the query model.
const Transaction = app.models.ReturningTransaction;
const connector = dataSource.connector;

return new Promise((resolve, reject) => {
connector.discoverReturningTransactions({}, (error, transactions) => {
if (error) {
return reject(error);
}

return transactions.reduce((promise, transaction) => {
return generateModelSchemas(connector, [transaction])
.then(schema => {
transaction.transactionSchema = schema[0];
registerReturningTransactionMethod(app, dataSource, Transaction, connector, transaction);
});
}, Promise.resolve([]));
});
});
}

module.exports = function (app, callback) {

// Get the Composer configuration.
Expand Down Expand Up @@ -757,6 +854,9 @@ module.exports = function (app, callback) {
if(modelDefinitions.length>0) {
// Register the named query methods, passing in whether we should use namespaces
registerQueryMethods(app, dataSource, modelDefinitions[0].namespaces);

// Register the returning transactions methods
registerReturningTransactionMethods(app, dataSource);
}

// For each model definition (type), we need to generate a Loopback model definition JSON file.
Expand Down
115 changes: 114 additions & 1 deletion packages/composer-rest-server/test/data/bond-network/lib/logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,119 @@ function publish(publishBond) {
});
}

/**
* Publish a new bond and return the concept response
* @param {org.acme.bond.PublishBondReturnConcept} publishBondReturnConcept - the publishBondReturnConcept transaction
* @returns {org.acme.bond.PublishBondResponse} response - The concept defining the structure of the response.
* @transaction
*/
async function publishBondReturnConcept(publishBondReturnConcept) {

const factory = getFactory();

const bondRegistry = await getAssetRegistry('org.acme.bond.BondAsset');
// Create the bond asset.
let bondAsset = factory.newResource('org.acme.bond', 'BondAsset', publishBondReturnConcept.ISINCode);
bondAsset.bond = publishBondReturnConcept.bond;
// Add the bond asset to the registry.
await bondRegistry.add(bondAsset);

// Build the concept response
let response = factory.newConcept('org.acme.bond', 'PublishBondResponse');
response.ISINCode = publishBondReturnConcept.ISINCode;
response.bondIssuer = publishBondReturnConcept.bond.issuer;
return response;
}

/**
* Publish a new bond and return the array of concept as response
* @param {org.acme.bond.PublishBondReturnConceptArray} publishBondReturnConceptArray - the publishBondReturnConcept transaction
* @returns {org.acme.bond.PublishBondResponse} response - The concept defining the structure of the response.
* @transaction
*/
async function publishBondReturnConceptArray(publishBondReturnConceptArray) {

const factory = getFactory();

const bondRegistry = await getAssetRegistry('org.acme.bond.BondAsset');
// Create the bond asset.
let bondAsset = factory.newResource('org.acme.bond', 'BondAsset', publishBondReturnConceptArray.ISINCode);
bondAsset.bond = publishBondReturnConceptArray.bond;
// Add the bond asset to the registry.
await bondRegistry.add(bondAsset);

let response = [];
let allBonds = await bondRegistry.getAll();
allBonds.forEach(bond => {
let bondConcept = factory.newConcept('org.acme.bond', 'PublishBondResponse');
bondConcept.ISINCode = bond.ISINCode;
bondConcept.bondIssuer = bond.bond.issuer;
response.push(bondConcept);
});
return response;
}

/**
* Publish a new bond and return the ISINCode
* @param {org.acme.bond.PublishBondReturnString} publishBondReturnString - the publishBondReturnString transaction
* @returns {string} (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string)
* @transaction
*/
async function publishBondReturnString(publishBondReturnString) {

const factory = getFactory();

const bondRegistry = await getAssetRegistry('org.acme.bond.BondAsset');
// Create the bond asset.
let bondAsset = factory.newResource('org.acme.bond', 'BondAsset', publishBondReturnString.ISINCode);
bondAsset.bond = publishBondReturnString.bond;
// Add the bond asset to the registry.
await bondRegistry.add(bondAsset);

// Build the response
return publishBondReturnString.ISINCode;
}

/**
* Publish a new bond and return the ISINCode
* @param {org.acme.bond.PublishBondReturnStringArray} publishBondReturnStringArray - the publishBondReturnStringArray transaction
* @returns {string[]} (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/string)
* @transaction
*/
async function publishBondReturnStringArray(publishBondReturnStringArray) {

const factory = getFactory();

const bondRegistry = await getAssetRegistry('org.acme.bond.BondAsset');
// Create the bond asset.
let bondAsset = factory.newResource('org.acme.bond', 'BondAsset', publishBondReturnStringArray.ISINCode);
bondAsset.bond = publishBondReturnStringArray.bond;
// Add the bond asset to the registry.
await bondRegistry.add(bondAsset);

// Build the response
return [publishBondReturnStringArray.ISINCode];
}

/**
* Publish a new bond and return the ISINCode
* @param {org.acme.bond.ExistsBond} existsBond - the existsBond transaction
* @returns {Boolean} - True if bond exists, False otherwise
* @transaction
*/
async function existsBond(existsBond) {

const factory = getFactory();

const bondRegistry = await getAssetRegistry('org.acme.bond.BondAsset');

// Get the bond from the bondRegistry
let bondAsset = bondRegistry.get(existsBond.ISINCode);

// Return true if bond exists
return !!bondAsset;
}

/**
* Publish a new bond
* @param {org.acme.bond.EmitBondEvent} emitBondEvent - the publishBond transaction
Expand Down Expand Up @@ -72,4 +185,4 @@ function multipleBondEventEmitter(emitMultipleBondEvents) {
}

/*eslint-enable no-unused-vars*/
/*eslint-enable no-undef*/
/*eslint-enable no-undef*/
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ participant Member identified by memberId {
}

participant Issuer extends Member {

}

enum PeriodEnum {
Expand Down Expand Up @@ -82,6 +82,41 @@ event BondEvent {
o String prop2
}

@returns(String)
transaction PublishBondReturnString {
o String ISINCode
o Bond bond
}

@returns(String[])
transaction PublishBondReturnStringArray {
o String ISINCode
o Bond bond
}

@returns(PublishBondResponse)
transaction PublishBondReturnConcept {
o String ISINCode
o Bond bond
}

@returns(PublishBondResponse[])
transaction PublishBondReturnConceptArray {
o String ISINCode
o Bond bond
}

@returns(Boolean)
@commit(false)
transaction ExistsBond {
o String ISINCode
}

concept PublishBondResponse {
o String ISINCode
--> Issuer bondIssuer
}

transaction EmitBondEvent {

}
Expand All @@ -95,17 +130,17 @@ abstract asset BaseAsset {
}

abstract concept BaseConcept {

}

abstract participant BaseParticipant {

}

abstract transaction BaseTransaction {

}

asset ExtendedBondAsset extends BondAsset {
o String[] arrayProp1
}
}
Loading

0 comments on commit d3d7794

Please sign in to comment.