Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for GraphQL API, starting with createEtchPacket #16

Merged
merged 18 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module is currently on v9.0.0 but have to drop to 6.0.0 to get it to work on Node 8

"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 = `{
newhouse marked this conversation as resolved.
Show resolved Hide resolved
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