This reference implementation models the implementation of data input and output functionalities in an extension app.
To test a read-only data IO extension app, modify the ReadOnlyManifest.json
file.
To test a data IO extension app with both read and write capabilities, modify the ReadWriteManifest.json
file.
Run the following command to clone the repository:
git clone https://github.com/docusign/extension-app-data-io-reference-implementation.git
- If you already have values for
JWT_SECRET_KEY
,OAUTH_CLIENT_ID
,OAUTH_CLIENT_SECRET
, andAUTHORIZATION_CODE
, you may skip this step.
The easiest way to generate a secret value is to run the following command:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'));"
You will need values for JWT_SECRET_KEY
, OAUTH_CLIENT_ID
, OAUTH_CLIENT_SECRET
, and AUTHORIZATION_CODE
.
- If you're running this in a development environment, create a copy of
example.development.env
and save it asdevelopment.env
. - If you're running this in a production environment, create a copy of
example.production.env
and save it asproduction.env
. - Replace
JWT_SECRET_KEY
,OAUTH_CLIENT_ID
,OAUTH_CLIENT_SECRET
, andAUTHORIZATION_CODE
indevelopment.env
orproduction.env
with your generated values. These values will be used to configure the sample proxy's mock authentication server. - Set the
clientId
value in the manifest file to the same value asOAUTH_CLIENT_ID
. - Set the
clientSecret
value in the manifest file to the same value asOAUTH_CLIENT_SECRET
.
Run the following command to install the necessary dependencies:
npm install
Start the proxy server in development mode by running the command:
npm run dev
This will create a local server on the port in the development.env
file (port 3000 by default) that listens for local changes that trigger a rebuild.
Start the proxy server in production mode by running the following commands:
npm run build
npm run start
This will start a production build on the port in the production.env
file (port 3000 by default).
Run the following command to create a public accessible tunnel to your localhost:
ngrok http <PORT>
Replace <PORT>
with the port number in the development.env
or production.env
file.
Copy the Forwarding
address from the response. You’ll need this address in your manifest file.
ngrok
Send your ngrok traffic logs to Datadog: https://ngrok.com/blog-post/datadog-log
Session Status online
Account email@domain.com (Plan: Free)
Update update available (version 3.3.1, Ctrl-U to update)
Version 3.3.0
Region United States (us)
Latency 60ms
Web Interface http://127.0.0.1:4040
Forwarding https://bbd7-12-202-171-35.ngrok-free.app -> http:
Connections ttl opn rt1 rt5 p50 p90
0 0 0.00 0.00 0.00 0.00
In this example, the Forwarding
address to copy is https://bbd7-12-202-171-35.ngrok-free.app
.
Replace <PROXY_BASE_URL>
in your manifest file with the ngrok forwarding address in the following sections:
connections.params.customConfig.profile.url
connections.params.customConfig.tokenUrl
connections.params.customConfig.authorizationUrl
actions.params.uri
- Replace this value for all of the actions.
2. Navigate to the Developer Console
Log in with your Docusign developer credentials and create a new app.
To create your extension app, open the Developer Console and select +New App. In the app manifest editor that opens, upload your manifest file or paste into the editor itself; then select Validate. Once the editor validates your manifest, select Create App.
This reference implementation uses mock data to simulate how data can be verified against a database. Test your extension using the sample data in fileDB.ts. Extension app tests include integration tests (connection tests and extension tests), functional tests, and App Center preview.
The Developer Console offers five extension tests to verify that a data IO extension app can connect to and exchange data with third-party APIs (or an API proxy that in turn connects with those APIs).
Note: These instructions only apply if you use the mock data in the reference implementation. If you use your own database, you’ll need to construct your requests based on your own schema. Queries for extension tests in the Developer Console are built using IQuery structure.
To begin the extension test process, run the CreateRecord test using the input provided in the Developer Console. The test should return a response containing the record ID.
All record types are located in the /src/db/
folder of this repository.
Open the sampleTypeName.json
file in the /src/db/
folder and check that the records were created.
This query searches the records that have been created. You don’t have to use the same sample values used here; the search should work with a valid attribute in sampleTypeName.json
.
Open the SearchRecords test and create a new query based on the sampleTypeName.json
file:
- The
from
attribute maps to the value oftypeName
in the CreateRecord query; in this case,sampleTypeName
. - The
data
array from the CreateRecord query maps to theattributesToSelect
array; in this case,sampleKey1
. - The
name
property of theleftOperand
object should be the value ofsampleKey1
; in this case,sampleValue1
. - The
operator
value should beEQUALS
. - The
name
property of therightOperand
object should be the same as what's inattributesToSelect
array; in this case,sampleKey1
.
The query below has been updated based on the directions above. You can copy and paste this into the SearchRecords test input box.
{
"query": {
"$class": "sampleQueryClass",
"attributesToSelect": [
"sampleKey1"
],
"from": "sampleTypeName",
"queryFilter": {
"$class": "sampleQueryFilterClass",
"operation": {
"$class": "sampleOperationClass",
"leftOperand": {
"$class": "sampleLeftOperandClass",
"name": "sampleValue1",
"type": "INTEGER",
"isLiteral": true
},
"operator": "EQUALS",
"rightOperand": {
"$class": "sampleRightOperandClass",
"name": "sampleKey1",
"type": "INTEGER",
"isLiteral": false
}
}
}
},
"pagination": {
"limit": 10,
"skip": 10
}
}
Running the test will return the record you queried.
The recordId
property in the sample input maps to an Id
in the sampleTypeName.json
file. Any valid record ID can be used in this field.
In the data
array, include any attributes and values to be added to the record. In this query, a new property will be added and the original data in the record will be updated.
{
"typeName": "sampleTypeName",
"recordId": "0",
"idempotencyKey": "sampleIdempotencyKey",
"data": {
"sampleKey1": "updatedSampleValue1",
"sampleKey2": "updatedSampleValue2",
"sampleKey3": "newSampleValue3"
}
}
Running the test should return the response "success": true
.
Rerun the SearchRecords extension test to search for the new patched values.
Input query:
"query": {
"$class": "sampleQueryClass",
"attributesToSelect": [
"sampleKey1"
],
"from": "sampleTypeName",
"queryFilter": {
"$class": "sampleQueryFilterClass",
"operation": {
"$class": "sampleOperationClass",
"leftOperand": {
"$class": "sampleLeftOperandClass",
"name": "updatedSampleValue1",
"type": "INTEGER",
"isLiteral": true
},
"operator": "EQUALS",
"rightOperand": {
"$class": "sampleRightOperandClass",
"name": "sampleKey1",
"type": "INTEGER",
"isLiteral": false
}
}
}
},
"pagination": {
"limit": 10,
"skip": 10
}
}
Results:
Alternatively, the sampleTypeName.json
file will contain the updated records.