Skip to content

Commit

Permalink
Merge pull request #16 from anvilco/newhouse/createEtchPacket
Browse files Browse the repository at this point in the history
Add support for GraphQL API, starting with createEtchPacket
  • Loading branch information
newhouse authored Sep 9, 2020
2 parents b79bd3f + 690bcd9 commit 051a78b
Show file tree
Hide file tree
Showing 14 changed files with 1,009 additions and 120 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ node_modules
package-lock.json
example/script/*.pdf
example/script/*.json

scratch/
60 changes: 46 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,9 @@ fs.writeFileSync('output.pdf', data, { encoding: null })

## API

### new Anvil(options)
### Instance Methods

##### new Anvil(options)

Creates an Anvil client instance.

Expand All @@ -57,18 +59,9 @@ Creates an Anvil client instance.
```js
const anvilClient = new Anvil({ apiKey: 'abc123' })
```
<br />

### Options

Options for the Anvil Client. Defaults are shown after each option key.

```js
{
apiKey: <your_api_key> // Required. Your API key from your Anvil organization settings
}
```

### Anvil::fillPDF(pdfTemplateID, payload[, options])
##### fillPDF(pdfTemplateID, payload[, options])

Fills a PDF with your JSON data.

Expand Down Expand Up @@ -115,15 +108,54 @@ const { statusCode, data } = await anvilClient.fillPDF(pdfTemplateID, payload, o
* `errors` (Array of Objects) - Will be present if status >= 400. See Errors
* `message` (String)

##### createEtchPacket(options)

Creates an Etch Packet and optionally sends it to the first signer.
* `options` (Object) - An object with the following structure:
* `variables` (Object) - See the [API Documentation](#api-documentation) area for details. See [Examples](#examples) area for examples.
* `responseQuery` (String) - _optional_ A GraphQL Query compliant query to use for the data desired in the mutation response. Can be left out to use default.

### Class Methods

##### prepareGraphQLFile(pathOrStreamOrBuffer[, options])
A nice helper to prepare a Stream-backed or Buffer-backed file upload for use with our GraphQL API.
* `pathOrStream` (String | Stream | Buffer) - An existing `Stream` OR an existing `Buffer` OR a string representing a fully resolved path to a file to be read into a new `Stream`.
* `options` (Object) - [UploadOptions](#uploadoptions) for the resulting object.
* Returns an `Object` that is properly formatted to be coerced by the client for use against our GraphQL API wherever an `Upload` type is required.

### Types

##### Options

Options for the Anvil Client. Defaults are shown after each option key.

```js
{
apiKey: <your_api_key> // Required. Your API key from your Anvil organization settings
}
```

##### UploadOptions

Options for the upload preparation class methods.
```js
{
filename: <filename>, // String
mimetype: <mimetype> // String
}
```

### Rate Limits

Our API has request rate limits in place. This API client handles `429 Too Many Requests` errors by waiting until it can retry again, then retrying the request. The client attempts to avoid `429` errors by throttling requests after the number of requests within the specified time period has been reached.

See the [Anvil API docs](https://useanvil.com/api/fill-pdf) for more information on the specifics of the rate limits.

### More Info
## API Documentation

Our general API Documentation can be found [here](https://www.useanvil.com/api/). It's the best resource for up-to-date information about our API and its capabilities.

See the [PDF filling API docs](https://useanvil.com/api/fill-pdf) for more information.
See the [PDF filling API docs](https://useanvil.com/api/fill-pdf) for more information about the `fillPDF` method.

## Examples

Expand Down
165 changes: 165 additions & 0 deletions example/script/create-etch-packet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
const path = require('path')
const Anvil = require('../../src/index')
const argv = require('yargs')
.usage('Usage: $0 apiKey orgEid castEid, fileName')
.demandCommand(4).argv

const [apiKey, orgEid, castEid, fileName] = argv._
const pathToFile = path.resolve(__dirname, fileName)

async function main () {
const clientOptions = {
apiKey,
}

const client = new Anvil(clientOptions)

// Example where pathToFile will be used to create a new Stream. Can also
// pass an existing Stream or Buffer
const streamFile = Anvil.prepareGraphQLFile(pathToFile)

const variables = {
organizationEid: orgEid,
send: false,
isTest: true,
signatureEmailSubject: 'Test Create Packet',
signers: [
{
id: 'signerOne',
name: 'Sally Signer',
email: 'sally@example.com',
fields: [
{
fileId: 'fileUpload',
fieldId: 'aDateField',
},
{
fileId: 'fileUpload',
fieldId: 'aSignatureField',
},
],
},
{
id: 'signerTwo',
name: 'Scotty Signer',
email: 'scotty@example.com',
fields: [
{
fileId: 'fileUpload',
fieldId: 'anotherSignatureField',
},
{
fileId: 'preExistingCastReference',
fieldId: 'signature1',
},
{
fileId: 'preExistingCastReference',
fieldId: 'signatureDate1',
},
],
},
],
fillPayload: {
payloads: {
fileUpload: {
textColor: '#CC0000',
data: {
myShortText: 'Something Filled',
},
},
preExistingCastReference: {
textColor: '#00CC00',
data: {
name: {
firstName: 'Robin',
lastName: 'Smith',
},
dateOfBirth: '2020-09-01',
socialSecurityNumber: '456454567',
primaryPhone: {
num: '5554443333',
},
},
},
},
},
files: [
{
id: 'fileUpload',
title: 'Important PDF One',
file: streamFile,
fields: [
{
id: 'myShortText',
type: 'shortText',
pageNum: 0,
rect: {
x: 20,
y: 100,
width: 100,
height: 30,
},
},
{
id: 'aDateField',
type: 'signatureDate',
pageNum: 1,
name: 'Some Date',
rect: {
x: 200,
y: 170,
width: 100,
height: 30,
},
},
{
id: 'aSignatureField',
type: 'signature',
name: 'Some Sig',
pageNum: 1,
rect: {
x: 200,
y: 120,
width: 100,
height: 30,
},
},
{
id: 'anotherSignatureField',
type: 'signature',
name: 'Another Sig',
pageNum: 1,
rect: {
x: 200,
y: 400,
width: 100,
height: 30,
},
},
],
},
{
id: 'preExistingCastReference',
castEid: castEid,
},
],
}

const { statusCode, data, errors } = await client.createEtchPacket({ variables })
console.log(
JSON.stringify({
statusCode,
data,
errors,
}),
)
}

main()
.then(() => {
process.exit(0)
})
.catch((err) => {
console.log(err.stack || err.message)
process.exit(1)
})
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "Anvil API Client",
"main": "src/index.js",
"scripts": {
"test": "mocha --require test/environment.js 'test/**/*.test.js'",
"test": "mocha --config ./test/mocha.js",
"test:watch": "nodemon --signal SIGINT --watch test --watch src -x 'yarn test'",
"version": "auto-changelog -p --template keepachangelog && git add CHANGELOG.md"
},
Expand All @@ -30,6 +30,7 @@
"devDependencies": {
"auto-changelog": "^1.16.2",
"babel-eslint": "^10.0.3",
"bdd-lazy-var": "^2.5.4",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"eslint": "^6.8.0",
Expand All @@ -49,7 +50,12 @@
"yargs": "^15.1.0"
},
"dependencies": {
"abort-controller": "^3.0.0",
"extract-files": "^6",
"form-data": "^3.0.0",
"limiter": "^1.1.5",
"lodash.get": "^4.4.2",
"mime-types": "^2.1.27",
"node-fetch": "^2.6.0"
},
"resolutions": {
Expand Down
5 changes: 5 additions & 0 deletions src/graphql/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const mutations = require('./mutations')

module.exports = {
mutations,
}
46 changes: 46 additions & 0 deletions src/graphql/mutations/createEtchPacket.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

const defaultResponseQuery = `{
id
eid
name
documentGroup {
id
eid
files
signers {
id
eid
name
email
}
}
}`

module.exports = {
getMutation: (responseQuery = defaultResponseQuery) => `
mutation CreateEtchPacket (
$name: String,
$organizationEid: String!,
$files: [EtchFile!],
$send: Boolean,
$isTest: Boolean,
$signatureEmailSubject: String,
$signatureEmailBody: String,
$signaturePageOptions: JSON,
$signers: [JSON!],
$fillPayload: JSON,
) {
createEtchPacket (
name: $name,
organizationEid: $organizationEid,
files: $files,
send: $send,
isTest: $isTest,
signatureEmailSubject: $signatureEmailSubject,
signatureEmailBody: $signatureEmailBody,
signaturePageOptions: $signaturePageOptions,
signers: $signers,
fillPayload: $fillPayload
) ${responseQuery}
}`,
}
11 changes: 11 additions & 0 deletions src/graphql/mutations/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const fs = require('fs')

const IGNORE_FILES = ['index.js']

module.exports = fs.readdirSync(__dirname)
.filter((fileName) => (fileName.endsWith('.js') && !fileName.startsWith('.') && !IGNORE_FILES.includes(fileName)))
.reduce((acc, fileName) => {
const mutationName = fileName.slice(0, fileName.length - 3)
acc[mutationName] = require(`./${mutationName}`)
return acc
}, {})
Loading

0 comments on commit 051a78b

Please sign in to comment.