Skip to content

Commit

Permalink
[FAB-13890] Additional Reference info
Browse files Browse the repository at this point in the history
-- Updated with corrections

Change-Id: Ic0c429b9ea81988d5e5a20b2afa834a0408c2327
Signed-off-by: Matthew B. White <whitemat@uk.ibm.com>
Signed-off-by: heatherlp <heatherpollard0@gmail.com>
  • Loading branch information
mbwhite authored and heatherlp committed Sep 25, 2019
1 parent f085675 commit 3d41093
Show file tree
Hide file tree
Showing 4 changed files with 300 additions and 9 deletions.
258 changes: 258 additions & 0 deletions docs/tutorials/annotated-contract-metadata.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@

# Annotated Contract Metadata

The Contract Metadata can be supplied either by the Contract developer or it can be inferred from the source code. Depending on the source language used, and the amount of annotations (if permitted by the language) you may need to augment the metadata that is generated.

## Metadata Schema

The metadata itself is in JSON, and there is a JSON-Schema definition that defines the contents; this schema is available online at http://fabric-shim.github.io/contract-schema.json

This is the latest ga copy of the schema. Specific version can be obtained using urls http://fabric-shim.github.io/{release}/contract-schema.json where releases matches the release name, for example
`master` `release-1.4`. Note that metadata was first introduced at v1.4.

A lot of the elements of this metadata are heavily inspired from the [OpenAPI v3.0 specification](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md) and [JSON Schema](http://json-schema.org/)

Adding a reference at the top of the metadata file to this schema, permits editors and tools to be able to perform validation on the JSON at the point of editing.

```json
{
"$schema": "http://fabric-shim.github.io/contract-schema.json",

}
```

If within the contract metadata is supplied, then this will be validated against the schema (even if the `$schema` field is not set). If this fails then the instantiating of the contract will fail.


## Supplying your own metadata
If you wish to supply your own metadata, the following rules apply

- it must be in a file called `metadata.json`
- this must be in a directory called `contract-metadata`
- this directory must be a peer of the package.json file of your contract

Depending on the language and implementation, you may only need to augment the metadata. For example, with Typescript the types of arguments can be derived. Typically a full 'info' section may be the only thing that needs augmenting. Therefore it is not required to specific all elements of the metadata

The metadata consists of three top level objects, 'info' 'contracts' and 'components'; you can supply all or none of these elements. (Supplying none is not considered an error, but has no practical effect)

The contents of each of these top level elements in your own metadata are used _in preference_ to any that can be automatically inferred.

_*It is a programming error to have logical inconsistencies between the 'contracts' and 'components' section.This could arise in the cases where the 'contracts' you specified is different from the automatically created 'components' section*_


## Overall structure

The metadata consists of three top level objects, 'info' 'contracts' and 'components'

### Info

*Purpose:*

To represent information about all the contracts defined in this chaincode module.

*Full Example:*
```json
"info": {
"title": "Commercial Paper Smart Contract",
"description": "Smart Contract definitions for Commercial Paper, issuing and trading",
"termsOfService": "http://example.com/terms/",
"contact": {
"name": "Peso Phillips",
"url": "http://www.example.com/support",
"email": "peso.phillips@example.com"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0.1"
}
```

*Minimal Example:*
```json
"info": {
"title": "Commercial Paper Smart Contract",
"version": "1.0.1"
}
```

*Structure:*

This has exactly the same elements, and requirements as OpenAPI's [info object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#infoObject).


### Contracts

*Purpose:*

This represents each contract class.

So for example the contracts object could be

```json
"contracts": {
"initUpgrade": {
...
},
"purchasing":{
...
},
"query": {
...
}
}
```
### Contract Object

*Purpose:*

Individual Contract object

*Structure:*

Each contract object has the following structure

```json
"CommercialPaper":{
"name": "CommercialPaper",
"info": {
...
},
"transactions":[
...
]
}
```

The name is the name of the contract, and is also the key value of the object. 'info' is the same OpenAPI info object as used at the top level of the metadata. It is not expected that the full form of this will be used with individual contracts.

Each 'transaction' represents the transaction functions within the contract (and will map, therefore, to a specific function in the code).

A starting example is a very simple transaction function.

```json
"transactions": [
{
"name": "setGreetingText",
"tag": [
"submitTx"
],
"parameters": [
{
"name": "text",
"description": "",
"schema": {
"type": "string"
}
},
{
"name": "value",
"schema": {
"$ref": "#/components/schemas/Greeting"
}
}
]

}
]
```

- the name of the function is 'setGreetingText'
- it has a tag of 'submitTx' that means that this transaction is intended to be submitted with the 'submitTransaction' sdk function. The implication is that this is then submitted to the orderder. If this is not present, then the function will be 'evaluated', not submitted to the order so in effect a query-style operation.
- the parameters of the function are defined in 'parameters' as an array of parameter definitions. (each of which follows the [parameterObject](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#parameterObject) of OpenAPI)
- typically a parameter will contain a 'name', optional 'description' and critically the 'schema'
- again 'schema' comes from OpenAPI [schemaObject](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject)
- In this example, there are two parameters one is a simple string, and the schema uses type to refer to this simply

```json
"schema": {
"type": "string"
}
```

Where as the second uses the concept of references to permit a more complex object definition.

### Components

This section defines the more complex components that can occur in functions. This is typicaly used to represent objects or similar in the contract. They are generated for example from the `@object` annotation.

In the above example, the schema is defined as
```json
"schema": {
"$ref": "#/components/schemas/Greeting"
}
```

The `#/components/schemas/Greeting` is a JSON pointer to the following element:
```json

"components": {
"schemas": {
"Greeting": {
"$id": "Greeting",
"type": "object",
"additionalProperties": false,
"properties": [
{
"name": "text",
"schema": {
"type": "string"
}
}
]
}
}
}

```

### Schema validation

The `schemas` section is an object listing the schemas (the key and $id element match).
Each of these has the specification from the OpenAPI [schemaObject](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject)

At runtime, any object that is supplied as one of the parameters matching a defined schema (in this case the Greeting object), has to match this supplied schema. The 'serializer' within the contract-api will produce a JSON representation of the object that is validated against this schema.

In this case for example, only the field 'text' is permitted - as additionalProperties is false. And has to be a string.

An other example would be to have a numeric value and limit its range.

```json
"age": {
"type": "integer",
"format": "int32",
"minimum": 0
}
```

Individual elements of an object can refer to other objects for example, and the overall object can define required fields.

This example is defining the concept of a person; who has a name, address and an age.

- The name is mandatory and has to exist,
- additional properties not listed here will be accepted.
- The address is defined elsewhere, and the age has to be at least 0

```json
"person" : {
"$id":"person",
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string"
},
"address": {
"$ref": "#/components/schemas/Address"
},
"age": {
"type": "integer",
"format": "int32",
"minimum": 0
}
}
}
```
6 changes: 3 additions & 3 deletions docs/tutorials/deep-dive-contract-interface.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Each Smart Contract package is, from a node perspective, a NPM module.
- index.js
- It is mandatory to have a `contracts` element exported that is a array of classes.
- Each of these classes must extend the `Contract` class from the `fabric-contract-api` module
- Optionally, a custom `serializer` may be defined to control how data is converted for transmission between chaincode, peer and ultimately client applications.
- Optionally, a custom `serializer` may be defined to control how data is converted for transmission between chaincode, peer and ultimately client applications (in future this could also include serialization to the ledger state).

*JavaScript example index.js*

Expand Down Expand Up @@ -117,7 +117,7 @@ A correctly specified metadata file, at the top level has this structure

```json
{
"$schema" : "https://fabric-shim.github.io/release-1.4/contract-schema.json",
"$schema" : "https://fabric-shim.github.io/master/contract-schema.json",
"info" : {

},
Expand All @@ -130,4 +130,4 @@ A correctly specified metadata file, at the top level has this structure
}
```

The metadata file that the user specifies has precedence over the information generated from the code, on a per section basis. If the user has not specified any of the above sections, then the 'gap' will be filled with auto generated values.
The metadata file that the user specifies has precedence over the information generated from the code, on a per section basis. If the user has not specified any of the above sections, then the 'gap' will be filled with auto generated values.
22 changes: 16 additions & 6 deletions docs/tutorials/tutorials.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
{
"using-chaincodeinterface":{
"title": "Using the Chaincode Interface"
"title":"Using the Chaincode Interface"
},
"using-contractinterface":{
"title": "Using the Contract Interface"
},
"using-iterators": {
"title": "Working with apis that return iterators"
}
"title":"Using the Contract Interface"
},
"using-iterators":{
"title":"Working with apis that return iterators"
},
"annotated-contract-metadata":{
"title":"Walkthrough of annotated metadata.json"
},
"deep-dive-contract-interface":{
"title":"Deep dive on Contract Interface"
},
"using-typescript-decorators":{
"title":"Using TypeScript Decorators"
}

}
23 changes: 23 additions & 0 deletions docs/tutorials/using-typescript-decorators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Summary of the Typescript Decorators

When using Typescript to code the Contract implementations, Typescript Decorators can be used to provide additional metadata; together with the type information that can be introspected, a very detailed set of metadata can be put within the source code directly.

## Decorators available

- @Info
- Supplies information about the following contract such as license terms or author.
- This takes as a parameter an object that has the key-value pairs as defined on the OpenAPI v3 [Info object spec](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#infoObject)
- @Transaction
- Defines the following function to be a callable transaction function
- Takes a boolean parameter; true indicates that this function is intended to be called with the 'submit' semantics, false indicates that this is intended to be called with the evaluate semantics. (Submit means submit to the orderer to be recorded on the ledger)
- Default is true
- @Returns
- Takes a string that is the name of the type that is being returned by this function
- This is present as required as Typescript does not give back the complete return type
- @Object
- Defines the class that represents one of the complex types that can be returned or passed to the transaction functions
- @Property
- Defines a property of the a class (identified by @Object) that should be passed within the object
- @Param
- Permits additional information such as a type and description to provided for parameters. (Note type is only useful in weakly typed languages)

0 comments on commit 3d41093

Please sign in to comment.