{"id":19901883,"url":"https://github.com/hyperledger/firefly-fabconnect","last_synced_at":"2025-04-06T00:07:25.501Z","repository":{"id":37080639,"uuid":"378972019","full_name":"hyperledger/firefly-fabconnect","owner":"hyperledger","description":"REST API to interact with a Fabric network and event streaming via websocket","archived":false,"fork":false,"pushed_at":"2025-03-11T17:10:49.000Z","size":1629,"stargazers_count":37,"open_issues_count":21,"forks_count":29,"subscribers_count":15,"default_branch":"main","last_synced_at":"2025-03-29T23:09:25.435Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hyperledger.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-21T15:08:39.000Z","updated_at":"2025-03-15T21:37:20.000Z","dependencies_parsed_at":"2024-01-17T18:21:03.041Z","dependency_job_id":"22aef991-3399-4604-977e-61471704bfd0","html_url":"https://github.com/hyperledger/firefly-fabconnect","commit_stats":null,"previous_names":["hyperledger-labs/firefly-fabconnect"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperledger%2Ffirefly-fabconnect","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperledger%2Ffirefly-fabconnect/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperledger%2Ffirefly-fabconnect/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hyperledger%2Ffirefly-fabconnect/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hyperledger","download_url":"https://codeload.github.com/hyperledger/firefly-fabconnect/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247415967,"owners_count":20935388,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-12T20:16:30.998Z","updated_at":"2025-04-06T00:07:25.479Z","avatar_url":"https://github.com/hyperledger.png","language":"Go","readme":"# firefly-fabconnect\n\nA reliable REST and websocket API to interact with a Fabric network and stream events.\n\nThis component provides 3 high level sets of API endpoints:\n\n- Client MSPs (aka the wallet): registering and enrolling identities to be used for signing transactions\n- Transactions: submit transactions and query for transaction result/receipts\n- Events: subscribe to events with regex based filter and stream to the client app via websocket\n\n## Architecture\n\n### High Level Components\n\n![high level architecture](/images/arch-1.jpg)\n\n### Objects and Flows\n\n![objects and flows architecture](/images/arch-2.png)\n![kafkal handler architecture](/images/arch-3.png)\n\n## Getting Started\n\nAfter checking out the repo, simply run `make` to build and test.\n\nTo launch, first prepare the 2 configurations files:\n\n- sample main config file:\n\n```json\n{\n  \"maxInFlight\": 10,\n  \"maxTXWaitTime\": 60,\n  \"sendConcurrency\": 25,\n  \"receipts\": {\n    \"maxDocs\": 1000,\n    \"queryLimit\": 100,\n    \"retryInitialDelay\": 5,\n    \"retryTimeout\": 30,\n    \"leveldb\": {\n      \"path\": \"/Users/me/Documents/ff-test/receipts\"\n    }\n  },\n  \"events\": {\n    \"webhooksAllowPrivateIPs\": true,\n    \"leveldb\": {\n      \"path\": \"/Users/me/Documents/ff-test/events\"\n    }\n  },\n  \"http\": {\n    \"port\": 3000\n  },\n  \"rpc\": {\n    \"useGatewayClient\": true,\n    \"configPath\": \"/Users/me/Documents/ff-test/ccp.yml\"\n  }\n}\n```\n\n// TODO clean this up\n- the standard Fabric common connection profile (CCP) file that describes the target Fabric network, at the location specified in the main config file above under `rpc.configPath`. For details on the CCP file, see [Fabric SDK documentation](https://hyperledger.github.io/fabric-sdk-node/release-1.4/tutorial-network-config.html). Note that the CCP file must contain the `client` section, which is required for the fabconnect to act as a client to Fabric networks.\n\nUse the following command to launch the connector:\n\n```\n./fabconnect -f \"/Users/me/Documents/ff-test/config.json\"\n```\n\n### API Specification\n\nThe API spec can be accessed at the endpoint `/api`, which is presented in the Swagger UI.\n\n![swagger ui](/images/swagger-ui.png)\n\n### Hierarchical Configurations\n\nEvery configuration parameter can be specified in one of the following ways:\n\n- configuration file that is specified with the `-f` command line parameter. this is overriden by...\n- environment variables that follows the naming convention:\n  - given a configuration property in the configuration JSON \"prop1.prop2\"\n  - capitalized, exchanging `.` with `_`, then add the `FC_` prefix\n  - becoming: `FC_PROP1_PROP2`\n  - this is overriden by...\n- command line parameter with a naming convention that follows the same dot-notaion of the property:\n  - given \"prop1.prop2\"\n  - the command line parameter should be `--prop1-prop2` or a shorthand variation\n\n### Support for both Static and Dynamic Network Topology\n\nThere is support for using a full connection profile that describes the entire network, without relying on the peer's discovery service to discover the list of peers to send transaction proposals to. A sample connection profile can be seen in the folder [test/fixture/ccp.yml](/test/fixture/ccp.yml). This mode will be running if both `rpc.useGatewayClient` and `rpc.useGatewayServer` are missing or set to `false`.\n\nThere is also support for using the dynamic gateway client by relying on the peer's discovery service with a minimal connection profile. A sample connection profile can be seen in the folder [test/fixture/ccp-short.yml](/test/fixture/ccp-short.yml). This mode will be running if `rpc.useGatewayClient` is set to `true`.\n\nSupport for server-based gateway support, available in Fabric 2.4, is coming soon.\n\n### Structured Data Support for Transaction Input with Schema Validation\n\nWhen calling the `POST /transactions` endpoint, input data can be provided in any of the following formats:\n\n- in the \"traditional\" array of strings corresponding to the target function's list of input parameters:\n\n```json\nPOST http://localhost:3000/transactions?fly-sync=true\u0026fly-signer=user001\u0026fly-channel=default-channel\u0026fly-chaincode=asset_transfer\n{\n    \"headers\": {\n        \"type\": \"SendTransaction\"\n    },\n    \"func\": \"CreateAsset\",\n    \"args\": [\"asset204\", \"red\", \"10\", \"Tom\", \"123000\"]\n}\n```\n\n- provide a `payloadSchema` property in the input payload `headers`, using [JSON Schema](https://json-schema.org/) to define the list of parameters. The root type must be an `array`, with `prefixItems` to define the sequence of parameters:\n\n```json\nPOST http://localhost:3000/transactions?fly-sync=true\u0026fly-signer=user001\u0026fly-channel=default-channel\u0026fly-chaincode=asset_transfer\n{\n    \"headers\": {\n        \"type\": \"SendTransaction\",\n        \"payloadSchema\": {\n            \"type\": \"array\",\n            \"prefixItems\": [{\n                \"name\": \"id\", \"type\": \"string\"\n            }, {\n                \"name\": \"color\", \"type\": \"string\"\n            }, {\n                \"name\": \"size\", \"type\": \"integer\"\n            }, {\n                \"name\": \"owner\", \"type\": \"string\"\n            }, {\n                \"name\": \"value\", \"type\": \"string\"\n            }]\n        }\n    },\n    \"func\": \"CreateAsset\",\n    \"args\": {\n        \"owner\": \"Tom\",\n        \"value\": \"123000\",\n        \"size\": 10,\n        \"id\": \"asset203\",\n        \"color\": \"red\"\n    }\n}\n```\n\n- when using `payloadSchema`, complex parameter structures are supported. Suppose the `CreateAsset` function has the following signature:\n\n```golang\ntype Asset struct {\n\tID             string `json:\"ID\"`\n\tColor          string `json:\"color\"`\n\tSize           int    `json:\"size\"`\n\tOwner          string `json:\"owner\"`\n\tAppraisal *Appraisal `json:\"appraisal\"`\n}\n\ntype Appraisal struct {\n\tAppraisedValue int  `json:\"appraisedValue\"`\n\tInspected      bool `json:\"inspected\"`\n}\n\n// CreateAsset issues a new asset to the world state with given details.\nfunc (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, color string, size int, owner string, appraisal Appraisal) error {\n  // implementation...\n}\n```\n\nNote that the `appraisal` parameter is a complex type, the transaction input data can be specified as follows:\n\n```json\nPOST http://localhost:3000/transactions?fly-sync=true\u0026fly-signer=user001\u0026fly-channel=default-channel\u0026fly-chaincode=asset_transfer\n{\n    \"headers\": {\n        \"type\": \"SendTransaction\",\n        \"payloadSchema\": {\n            \"type\": \"array\",\n            \"prefixItems\": [{\n                \"name\": \"id\", \"type\": \"string\"\n            }, {\n                \"name\": \"color\", \"type\": \"string\"\n            }, {\n                \"name\": \"size\", \"type\": \"integer\"\n            }, {\n                \"name\": \"owner\", \"type\": \"string\"\n            }, {\n                \"name\": \"appraisal\", \"type\": \"object\",\n                \"properties\": {\n                    \"appraisedValue\": {\n                        \"type\": \"integer\"\n                    },\n                    \"inspected\": {\n                        \"type\": \"boolean\"\n                    }\n                }\n            }]\n        }\n    },\n    \"func\": \"CreateAsset\",\n    \"args\": {\n        \"owner\": \"Tom\",\n        \"appraisal\": {\n            \"appraisedValue\": 123000,\n            \"inspected\": true\n        },\n        \"size\": 10,\n        \"id\": \"asset205\",\n        \"color\": \"red\"\n    }\n}\n```\n\n### JSON Data Support in Events\n\nIf a chaincode publishes events with string or JSON data, fabconnect can be instructed to decode them from the byte array before sending the event to the listening client application. The decoding instructions can be provided during subscription.\n\nFor example, the following chaincode publishes an event containing a JSON structure in the payload:\n\n```golang\n\tasset := Asset{\n\t\tID:             id,\n\t\tColor:          color,\n\t\tSize:           size,\n\t\tOwner:          owner,\n\t\tAppraisal: \u0026Appraisal{\n\t\t\tAppraisedValue: appraisal.AppraisedValue,\n\t\t\tInspected: appraisal.inspected,\n\t\t},\n\t}\n\tassetJSON, _ := json.Marshal(asset)\n\tctx.GetStub().SetEvent(\"AssetCreated\", assetJSON)\n```\n\nAn event subscription can be created as follows which contains instructions to decode the payload bytes:\n\n```json\n{\n  \"stream\": \"es-31e85b01-6440-4cc3-63e9-2aafc0d06466\",\n  \"channel\": \"default-channel\",\n  \"name\": \"sub-1\",\n  \"signer\": \"user001\",\n  \"fromBlock\": \"100\",\n  \"filter\": {\n    \"chaincodeId\": \"assettransfercomplex\"\n  },\n  \"payloadType\": \"string\"\n}\n```\n\nNotice the `payloadType` property, which instructs fabconnect to decode the payload bytes into a JSON structure. As a result the client will receive the event JSON as follows:\n\n```json\n[\n  {\n    \"chaincodeId\": \"assettransfercomplex\",\n    \"blockNumber\": 151,\n    \"transactionId\": \"8692254ea13e9f5cb021b613e722ce4610daa5c4529e1a9161497308b0278ca0\",\n    \"eventName\": \"AssetCreated\",\n    \"payload\": {\n      \"ID\": \"asset204\",\n      \"appraisal\": {\n        \"appraisedValue\": 123000,\n        \"inspected\": true\n      },\n      \"color\": \"red\",\n      \"owner\": \"Tom\",\n      \"size\": 10\n    },\n    \"subId\": \"sb-6859f687-61dd-44e8-6e8b-ddcf3b95b840\"\n  }\n]\n```\n\nBesides `stringifiedJSON`, `string` is also supported as the payload type which represents UTF-8 encoded strings.\n\n### Fixes Needed for multiple subscriptions under the same event stream\n\nThe current `fabric-sdk-go` uses an internal cache for event services, which builds keys only using the channel ID. This means if there are multiple subscriptions targeting the same channel, but specify different `fromBlock` parameters, only the first instance will be effective. All subsequent subscriptions will share the same event service, rendering their own `fromBlock` configuration ineffective.\n\nA fix has been provided for this in the forked repository [https://github.com/kaleido-io/fabric-sdk-go](https://github.com/kaleido-io/fabric-sdk-go).\n\nFollow these simple steps to integrate this fix (until it's contributed back to the official repo):\n\n- clone the repository https://github.com/kaleido-io/fabric-sdk-go and place it peer to the `firefly-fabconnect` folder:\n  ```\n  workspace-root\n     \\_ fabric-sdk-go\n     \\_ firefly-fabconnect\n  ```\n- checkout branch `eventservice-cache-key`\n- configure go to use it instead of the official package:\n  ```\n  go mod edit -replace=github.com/hyperledger/fabric-sdk-go=../fabric-sdk-go\n  ```\n- rebuild with `make`\n\n### License\n\nThis project is licensed under the Apache 2 License - see the [`LICENSE`](LICENSE) file for details.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperledger%2Ffirefly-fabconnect","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhyperledger%2Ffirefly-fabconnect","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhyperledger%2Ffirefly-fabconnect/lists"}