zapier-platform-cli 12.0.2 → 12.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-source.md +2033 -0
- package/README.md +122 -95
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
- package/src/oclif/commands/migrate.js +44 -10
- package/src/oclif/commands/promote.js +21 -7
- package/src/oclif/commands/team/add.js +26 -13
- package/src/oclif/commands/team/get.js +17 -21
- package/src/oclif/commands/team/remove.js +23 -26
- package/src/utils/build.js +17 -1
- package/src/utils/team.js +33 -0
package/README.md
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
<!-- GENERATED! ONLY EDIT `README-source.md` -->
|
|
2
2
|
|
|
3
3
|
<h1 align="center">
|
|
4
|
-
<
|
|
4
|
+
<picture>
|
|
5
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.zappy.app/11069978ee4a9b1eeeeb62b11f541b7c.png">
|
|
6
|
+
<source media="(prefers-color-scheme: light)" srcset="https://cdn.zappy.app/2602734341239f1b82ef0ff4ca160430.png">
|
|
7
|
+
<img alt="Zapier Logo" src="https://cdn.zappy.app/2602734341239f1b82ef0ff4ca160430.png" width="300px">
|
|
8
|
+
</picture>
|
|
5
9
|
<br>
|
|
6
|
-
|
|
10
|
+
Platform CLI
|
|
7
11
|
<br>
|
|
8
12
|
<br>
|
|
9
13
|
</h1>
|
|
@@ -22,7 +26,7 @@ You may find docs duplicate or outdated across the Zapier site. The most up-to-d
|
|
|
22
26
|
|
|
23
27
|
Our code is updated frequently. To see a full list of changes, look no further than [the CHANGELOG](https://github.com/zapier/zapier-platform/blob/master/CHANGELOG.md).
|
|
24
28
|
|
|
25
|
-
This doc describes the latest CLI version (**12.0
|
|
29
|
+
This doc describes the latest CLI version (**12.1.0**), as of this writing. If you're using an older version of the CLI, you may want to check out these historical releases:
|
|
26
30
|
|
|
27
31
|
- CLI Docs: [10.2.0](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@10.2.0/packages/cli/README.md), [9.6.0](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@9.6.0/packages/cli/README.md), [8.4.2](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@8.4.2/packages/cli/README.md)
|
|
28
32
|
- CLI Reference: [10.2.0](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@10.2.0/packages/cli/docs/cli.md), [9.6.0](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@9.6.0/packages/cli/docs/cli.md), [8.4.2](https://github.com/zapier/zapier-platform/blob/zapier-platform-cli@8.4.2/packages/cli/docs/cli.md)
|
|
@@ -55,6 +59,7 @@ This doc describes the latest CLI version (**12.0.2**), as of this writing. If y
|
|
|
55
59
|
* [Session](#session)
|
|
56
60
|
* [OAuth1](#oauth1)
|
|
57
61
|
* [OAuth2](#oauth2)
|
|
62
|
+
* [Connection Label](#connection-label)
|
|
58
63
|
- [Resources](#resources)
|
|
59
64
|
* [Resource Definition](#resource-definition)
|
|
60
65
|
- [Triggers/Searches/Creates](#triggerssearchescreates)
|
|
@@ -191,7 +196,7 @@ You can develop using any version of Node you'd like, but your eventual code mus
|
|
|
191
196
|
|
|
192
197
|
To ensure stability for our users, we strongly encourage you run tests on `v14` sometime before your code reaches users. This can be done multiple ways.
|
|
193
198
|
|
|
194
|
-
Firstly, by using a CI tool (like [Travis CI](https://travis-ci.org/) or [Circle CI](https://circleci.com/), which are free for open source projects). We provide a sample [.travis.yml](https://github.com/zapier/zapier-platform/blob/master/example-apps/
|
|
199
|
+
Firstly, by using a CI tool (like [Travis CI](https://travis-ci.org/) or [Circle CI](https://circleci.com/), which are free for open source projects). We provide a sample [.travis.yml](https://github.com/zapier/zapier-platform/blob/master/example-apps/trigger/.travis.yml) file in our template apps to get you started.
|
|
195
200
|
|
|
196
201
|
Alternatively, you can change your local node version with tools such as [nvm](https://github.com/nvm-sh/nvm#installation-and-update). Then you can either swap to that version with `nvm use v14`, or do `nvm exec v14 zapier test` so you can run tests without having to switch versions while developing.
|
|
197
202
|
|
|
@@ -207,6 +212,7 @@ npm install -g zapier-platform-cli
|
|
|
207
212
|
# setup auth to Zapier's platform with a deploy key
|
|
208
213
|
zapier login
|
|
209
214
|
```
|
|
215
|
+
> Note: If you log into Zapier via the single sign-on (Google, Facebook, or Microsoft), you may not have a Zapier password. If that's the case, you'll need to generate a deploy key, go to [your Zapier developer accont here](https://zapier.com/developer/partner-settings/deploy-keys/) and create/copy a key, then run ```zapier login``` command with the --sso flag.
|
|
210
216
|
|
|
211
217
|
Your Zapier CLI should be installed and ready to go at this point. Next up, we'll create our first app!
|
|
212
218
|
|
|
@@ -221,7 +227,7 @@ cd example-app
|
|
|
221
227
|
npm install
|
|
222
228
|
```
|
|
223
229
|
|
|
224
|
-
> Note:
|
|
230
|
+
> Note: When you run `zapier init`, you'll be presented with a list of templates to start with. Pick the one that matches a feature you'll need (such as "dynamic-dropdown" for an integration with [dynamic dropdown fields](#dynamic-dropdowns)), or select "minimal" for an integration with only the essentials. [View more example apps here](https://github.com/zapier/zapier-platform/tree/master/example-apps).
|
|
225
231
|
|
|
226
232
|
You should now have a working local app. You can run several local commands to try it out.
|
|
227
233
|
|
|
@@ -442,15 +448,15 @@ zapier convert 1234 --version 1.0.1 my-app
|
|
|
442
448
|
|
|
443
449
|
## Authentication
|
|
444
450
|
|
|
445
|
-
Most applications require some sort of authentication
|
|
451
|
+
Most applications require some sort of authentication. The Zapier platform provides core behaviors for several common authentication methods that might be used with your application, as well as the ability to customize authentication further.
|
|
446
452
|
|
|
447
|
-
|
|
453
|
+
When a user authenticates to your application through Zapier, a "connection" is created representing their authentication details. Data tied to a specific authentication connection is included in the [bundle object](#bundle-object) under `bundle.authData`.
|
|
448
454
|
|
|
449
455
|
### Basic
|
|
450
456
|
|
|
451
457
|
Useful if your app requires two pieces of information to authenticate: `username` and `password`, which only the end user can provide. By default, Zapier will do the standard Basic authentication base64 header encoding for you (via an automatically registered middleware).
|
|
452
458
|
|
|
453
|
-
>
|
|
459
|
+
> To create a new integration with basic authentication, run `zapier init [your app name] --template basic-auth`. You can also review an example of that code [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/basic-auth).
|
|
454
460
|
|
|
455
461
|
If your app uses Basic auth with an encoded API key rather than a username and password, like `Authorization: Basic APIKEYHERE:x`, consider the [Custom](#custom) authentication method instead.
|
|
456
462
|
|
|
@@ -477,11 +483,11 @@ const App = {
|
|
|
477
483
|
|
|
478
484
|
*New in v7.4.0.*
|
|
479
485
|
|
|
480
|
-
The setup and user experience of Digest Auth is identical to Basic Auth. Users
|
|
486
|
+
The setup and user experience of Digest Auth is identical to Basic Auth. Users provide Zapier their username and password, and Zapier handles all the nonce and quality of protection details automatically.
|
|
481
487
|
|
|
482
|
-
>
|
|
488
|
+
> To create a new integration with digest authentication, run `zapier init [your app name] --template digest-auth`. You can also review an example of that code [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/digest-auth).
|
|
483
489
|
|
|
484
|
-
> Limitation: Currently, MD5-sess and SHA are not implemented. Only the MD5 algorithm is supported. In addition, server nonces are not reused. That means for every `z.request` call, Zapier will
|
|
490
|
+
> Limitation: Currently, MD5-sess and SHA are not implemented. Only the MD5 algorithm is supported. In addition, server nonces are not reused. That means for every `z.request` call, Zapier will send an additional request beforehand to get the server nonce.
|
|
485
491
|
|
|
486
492
|
```js
|
|
487
493
|
const getConnectionLabel = (z, bundle) => {
|
|
@@ -510,9 +516,9 @@ const App = {
|
|
|
510
516
|
|
|
511
517
|
### Custom
|
|
512
518
|
|
|
513
|
-
|
|
519
|
+
Custom auth is most commonly used for apps that authenticate with API keys, although it also provides flexibility for any unusual authentication setup. You'll likely provide some custom `beforeRequest` middleware or a `requestTemplate` (see [Making HTTP Requests](#making-http-requests)) to pass in data returned from the authentication process, most commonly by adding/computing needed headers.
|
|
514
520
|
|
|
515
|
-
>
|
|
521
|
+
> To create a new integration with custom authentication, run `zapier init [your app name] --custom-auth`. You can also review an example of that code [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/custom-auth).
|
|
516
522
|
|
|
517
523
|
```js
|
|
518
524
|
const authentication = {
|
|
@@ -558,9 +564,9 @@ const App = {
|
|
|
558
564
|
|
|
559
565
|
### Session
|
|
560
566
|
|
|
561
|
-
|
|
567
|
+
Session auth gives you the ability to exchange some user-provided data for some authentication data; for example, username and password for a session key. It can be used to implement almost any authentication method that uses that pattern - for example, alternative OAuth flows.
|
|
562
568
|
|
|
563
|
-
>
|
|
569
|
+
> To create a new integration with session authentication, run `zapier init [your app name] --template session-auth`. You can also review an example of that code [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/session-auth).
|
|
564
570
|
|
|
565
571
|
```js
|
|
566
572
|
const getSessionKey = async (z, bundle) => {
|
|
@@ -628,15 +634,15 @@ const App = {
|
|
|
628
634
|
|
|
629
635
|
```
|
|
630
636
|
|
|
631
|
-
|
|
637
|
+
For Session auth, the function that fetches the additional authentication data needed to make API calls (`authentication.sessionConfig.perform`) has the user-provided fields in `bundle.inputData`. Afterwards, `bundle.authData` contains the data returned by that function (usually the session key or token).
|
|
632
638
|
|
|
633
639
|
### OAuth1
|
|
634
640
|
|
|
635
641
|
*New in `v7.5.0`.*
|
|
636
642
|
|
|
637
|
-
Zapier's OAuth1 implementation matches [Twitter
|
|
643
|
+
Zapier's OAuth1 implementation matches [Twitter](https://developer.twitter.com/en/docs/tutorials/authenticating-with-twitter-api-for-enterprise/authentication-method-overview#oauth1.0a) and [Trello](https://developer.atlassian.com/cloud/trello/guides/rest-api/authorization/#using-basic-oauth) implementations of the 3-legged OAuth flow.
|
|
638
644
|
|
|
639
|
-
>
|
|
645
|
+
> To create a new integration with OAuth1, run `zapier init [your app name] --template oauth1-trello`. You can also check out [oauth1-trello](https://github.com/zapier/zapier-platform/tree/master/example-apps/oauth1-trello), [oauth1-tumblr](https://github.com/zapier/zapier-platform/tree/master/example-apps/oauth1-tumblr), and [oauth1-twitter](https://github.com/zapier/zapier-platform/tree/master/example-apps/oauth1-twitter) for working example apps with OAuth1.
|
|
640
646
|
|
|
641
647
|
The flow works like this:
|
|
642
648
|
|
|
@@ -748,13 +754,15 @@ module.exports = App;
|
|
|
748
754
|
|
|
749
755
|
```
|
|
750
756
|
|
|
751
|
-
|
|
757
|
+
For OAuth1, `authentication.oauth1Config.getRequestToken`, `authentication.oauth1Config.authorizeUrl`, and `authentication.oauth1Config.getAccessToken` have fields like `redirect_uri` and the temporary credentials in `bundle.inputData`. After `getAccessToken` runs, the resulting token value(s) will be stored in `bundle.authData` for the connection.
|
|
758
|
+
|
|
759
|
+
Also, `authentication.oauth1Config.getAccessToken` has access to the additional return values in `rawRequest` and `cleanedRequest` should you need to extract other values (for example, from the query string).
|
|
752
760
|
|
|
753
761
|
### OAuth2
|
|
754
762
|
|
|
755
763
|
Zapier's OAuth2 implementation is based on the `authorization_code` flow, similar to [GitHub](https://developer.github.com/v3/oauth/) and [Facebook](https://developers.facebook.com/docs/authentication/server-side/).
|
|
756
764
|
|
|
757
|
-
>
|
|
765
|
+
> To create a new integration with OAuth2, run `zapier init [your app name] --template oauth2`. You can also check out [our working example app](https://github.com/zapier/zapier-platform/tree/master/example-apps/oauth2).
|
|
758
766
|
|
|
759
767
|
If your app's OAuth2 flow uses a different grant type, such as `client_credentials`, try using [Session auth](#session) instead.
|
|
760
768
|
|
|
@@ -771,7 +779,7 @@ You are required to define:
|
|
|
771
779
|
* `authorizeUrl`: The authorization URL
|
|
772
780
|
* `getAccessToken`: The API call to fetch the access token
|
|
773
781
|
|
|
774
|
-
If the access token has a limited life and you want to refresh the token when it expires, you'll also need to define the API call to perform that refresh. You can choose to set `autoRefresh: true`, as in the example app, if you want Zapier to automatically make a call to refresh the token after receiving a 401. See [Stale Authentication Credentials](#stale-authentication-credentials) for more details on handling auth refresh.
|
|
782
|
+
If the access token has a limited life and you want to refresh the token when it expires, you'll also need to define the API call to perform that refresh (`refreshAccessToken`). You can choose to set `autoRefresh: true`, as in the example app, if you want Zapier to automatically make a call to refresh the token after receiving a 401. See [Stale Authentication Credentials](#stale-authentication-credentials) for more details on handling auth refresh.
|
|
775
783
|
|
|
776
784
|
You'll also likely want to set your `CLIENT_ID` and `CLIENT_SECRET` as environment variables:
|
|
777
785
|
|
|
@@ -855,7 +863,21 @@ module.exports = App;
|
|
|
855
863
|
|
|
856
864
|
```
|
|
857
865
|
|
|
858
|
-
|
|
866
|
+
For OAuth2, `authentication.oauth2Config.authorizeUrl`, `authentication.oauth2Config.getAccessToken`, and `authentication.oauth2Config.refreshAccessToken` have fields like `redirect_uri` and `state` in `bundle.inputData`. After the code is exchanged for an access token and/or refresh token, those tokens are stored in `bundle.authData` for the connection.
|
|
867
|
+
|
|
868
|
+
Also, `authentication.oauth2Config.getAccessToken` has access to the additional return values in `rawRequest` and `cleanedRequest` should you need to extract other values (for example, from the query string).
|
|
869
|
+
|
|
870
|
+
### Connection Label
|
|
871
|
+
|
|
872
|
+
When a user connects to your app via Zapier and a connection is created to hold the related data in `bundle.authData`, the connection is automatically labeled with the app name. You also have the option of setting a connection label (`connectionLabel`), which can be extremely helpful to identify information like which user is connected or what instance of your app they are connected to. That way, users don't get confused if they have multiple connections to your app.
|
|
873
|
+
|
|
874
|
+
When setting a connection label, you can use either a string with variable references (as shown in [Basic Auth](#basic)) or a function (as shown in [Digest Auth](#digest)).
|
|
875
|
+
|
|
876
|
+
When using a string, you have access to the information in `bundle.authData` and the information returned from the test request in `bundle.inputData`, all at the top level. So in Basic auth, if `connectionLabel` is `{{username}}`, that refers to the username used for authentication.
|
|
877
|
+
|
|
878
|
+
When using a function, this "hoisting" of data to the top level is skipped, and you must refer to data items by their fully qualified name, as shown in the line `return bundle.inputData.username;` in the Digest Auth snippet. `return username;` would not work in this context.
|
|
879
|
+
|
|
880
|
+
**NOTE:** Do not use sensitive authentication data such as passwords or API keys in the connection label. It's visible in plain text on Zapier. The purpose of the label is to identify the connection for the user, so stick with data such as username or instance identifier that is meaningful but not sensitive.
|
|
859
881
|
|
|
860
882
|
|
|
861
883
|
## Resources
|
|
@@ -895,7 +917,7 @@ This will generate the resource file and add the necessary statements to the `in
|
|
|
895
917
|
A resource has a few basic properties. The first is the `key`, which allows Zapier to identify the resource on our backend.
|
|
896
918
|
The second is the `noun`, the user-friendly name of the resource that is presented to users throughout the Zapier UI.
|
|
897
919
|
|
|
898
|
-
>
|
|
920
|
+
> Check out [this working example app](https://github.com/zapier/zapier-platform/tree/master/example-apps/resource) to see resources in action.
|
|
899
921
|
|
|
900
922
|
After those, there is a set of optional properties that tell Zapier what methods can be performed on the resource.
|
|
901
923
|
The complete list of available methods can be found in the [Resource Schema Docs](https://github.com/zapier/zapier-platform/blob/master/packages/schema/docs/build/schema.md#resourceschema).
|
|
@@ -1000,14 +1022,9 @@ const App = {
|
|
|
1000
1022
|
You can find more details on the definition for each by looking at the [Trigger Schema](https://github.com/zapier/zapier-platform/blob/master/packages/schema/docs/build/schema.md#triggerschema),
|
|
1001
1023
|
[Search Schema](https://github.com/zapier/zapier-platform/blob/master/packages/schema/docs/build/schema.md#searchschema), and [Create Schema](https://github.com/zapier/zapier-platform/blob/master/packages/schema/docs/build/schema.md#createschema).
|
|
1002
1024
|
|
|
1003
|
-
>
|
|
1004
|
-
|
|
1005
|
-
> Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/rest-hooks for a working example app using REST hook triggers.
|
|
1006
|
-
|
|
1007
|
-
> Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/search for a working example app using searches.
|
|
1008
|
-
|
|
1009
|
-
> Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/create for a working example app using creates.
|
|
1025
|
+
> To create a new integration with a premade trigger, search, or create, run `zapier init [your app name]` and select from the list that appears. You can also check out our working example apps [here](https://github.com/zapier/zapier-platform/tree/master/example-apps).
|
|
1010
1026
|
|
|
1027
|
+
> To add a trigger, search, or create to an existing integration, run `zapier scaffold [trigger|search|create] [noun]` to create the necessary files to your project. For example, `zapier scaffold trigger post` will create a new trigger called "New Post".
|
|
1011
1028
|
### Return Types
|
|
1012
1029
|
|
|
1013
1030
|
Each of the 3 types of function expects a certain type of object. As of core v1.0.11, there are automated checks to let you know when you're trying to pass the wrong type back. For reference, each expects:
|
|
@@ -1034,7 +1051,7 @@ In cases where Zapier needs to show an example record to the user, but we are un
|
|
|
1034
1051
|
|
|
1035
1052
|
On each trigger, search, or create in the `operation` directive - you can provide an array of objects as fields under the `inputFields`. Input Fields are what your users would see in the main Zapier user interface. For example, you might have a "Create Contact" action with fields like "First name", "Last name", "Email", etc. These fields will be able to accept input from previous steps in a Zap, for example:
|
|
1036
1053
|
|
|
1037
|
-

|
|
1038
1055
|
|
|
1039
1056
|
You can find more details about setting action fields from a user perspective in [our help documentation](https://zapier.com/help/creating-zap/#set-up-action-template).
|
|
1040
1057
|
|
|
@@ -1073,7 +1090,7 @@ You can find more details on the different field schema options at [our Field Sc
|
|
|
1073
1090
|
|
|
1074
1091
|
### Custom/Dynamic Fields
|
|
1075
1092
|
|
|
1076
|
-
In some cases,
|
|
1093
|
+
In some cases, you may need to provide dynamically-generated fields - especially for custom ones. This is common functionality for CRMs, form software, databases, and other highly-customizable platforms. Instead of an explicit field definition, you can provide a function we'll evaluate to return a list of fields - merging the dynamic with the static fields.
|
|
1077
1094
|
|
|
1078
1095
|
> You should see `bundle.inputData` partially filled in as users provide data - even in field retrieval. This allows you to build hierarchical relationships into fields (e.g. only show issues from the previously selected project).
|
|
1079
1096
|
|
|
@@ -1083,7 +1100,7 @@ In some cases, it might be necessary to provide fields that are dynamically gene
|
|
|
1083
1100
|
const recipeFields = async (z, bundle) => {
|
|
1084
1101
|
const response = await z.request('https://example.com/api/v2/fields.json');
|
|
1085
1102
|
|
|
1086
|
-
// Call
|
|
1103
|
+
// Call response.throwForStatus() if you're using zapier-platform-core v9 or older
|
|
1087
1104
|
|
|
1088
1105
|
// Should return an array like [{"key":"field_1"},{"key":"field_2"}]
|
|
1089
1106
|
return response.data; // response.json if you're using core v9 or older
|
|
@@ -1118,7 +1135,7 @@ const App = {
|
|
|
1118
1135
|
|
|
1119
1136
|
```
|
|
1120
1137
|
|
|
1121
|
-
Additionally, if there is a field that affects the generation of dynamic fields, you can set the `altersDynamicFields: true
|
|
1138
|
+
Additionally, if there is a field that affects the generation of dynamic fields, you can set the property `altersDynamicFields: true`. This informs the Zapier UI whenever the value of that field changes, the input fields need to be recomputed. For example, imagine the selection on a static dropdown called "Dessert Type" determining whether the function generating dynamic fields includes the field "With Sprinkles?" or not. If the value in one input field affects others, this is an important property to set.
|
|
1122
1139
|
|
|
1123
1140
|
```js
|
|
1124
1141
|
module.exports = {
|
|
@@ -1156,8 +1173,8 @@ module.exports = {
|
|
|
1156
1173
|
When using dynamic fields, the fields will be retrieved in three different contexts:
|
|
1157
1174
|
|
|
1158
1175
|
* Whenever the value of a field with `altersDynamicFields` is changed, as described above.
|
|
1159
|
-
* Whenever Zap Editor opens the "Set up" section for the trigger or action.
|
|
1160
|
-
* Whenever the Refresh
|
|
1176
|
+
* Whenever the Zap Editor opens the "Set up" section for the trigger or action.
|
|
1177
|
+
* Whenever the "Refresh fields" button at the bottom of the Editor's "Set up" section is clicked.
|
|
1161
1178
|
|
|
1162
1179
|
Be sure to set up your code accordingly - for example, don't rely on any input fields already having a value, since they won't have one the first time the "Set up" section loads.
|
|
1163
1180
|
|
|
@@ -1216,7 +1233,7 @@ In the above code example the dynamic property makes reference to a trigger with
|
|
|
1216
1233
|
```
|
|
1217
1234
|
|
|
1218
1235
|
The dynamic dropdown would look something like this.
|
|
1219
|
-

|
|
1220
1237
|
|
|
1221
1238
|
In the first code example the dynamic dropdown is powered by a trigger. You can also use a resource to power a dynamic dropdown. To do this combine the resource key and the resource method using camel case.
|
|
1222
1239
|
|
|
@@ -1723,7 +1740,7 @@ This object holds the user's auth details and the data for the API requests.
|
|
|
1723
1740
|
|
|
1724
1741
|
### `bundle.inputData`
|
|
1725
1742
|
|
|
1726
|
-
`bundle.inputData` is user-provided data for this particular run of the trigger/search/create, as defined by the `inputFields
|
|
1743
|
+
`bundle.inputData` is user-provided data for this particular run of the trigger/search/create, as defined by the [`inputFields`](#input-fields). For example:
|
|
1727
1744
|
|
|
1728
1745
|
```js
|
|
1729
1746
|
{
|
|
@@ -1977,22 +1994,22 @@ const App = {
|
|
|
1977
1994
|
|
|
1978
1995
|
## Making HTTP Requests
|
|
1979
1996
|
|
|
1980
|
-
There are two
|
|
1997
|
+
There are two ways to make HTTP requests:
|
|
1981
1998
|
|
|
1982
|
-
1. **Shorthand HTTP Requests** -
|
|
1983
|
-
2. **Manual HTTP Requests** - you
|
|
1999
|
+
1. [**Shorthand HTTP Requests**](#shorthand-http-requests) - Easy to use, but limits what you can control. Best for simple requests.
|
|
2000
|
+
2. [**Manual HTTP Requests**](#manual-http-requests) - Gives you full control over the request and response.
|
|
1984
2001
|
|
|
1985
|
-
|
|
2002
|
+
Use these helper constructs to reduce boilerplate:
|
|
1986
2003
|
|
|
1987
|
-
1. `requestTemplate`
|
|
1988
|
-
2. `beforeRequest` middleware
|
|
1989
|
-
3. `afterResponse` middleware
|
|
2004
|
+
1. `requestTemplate` - an object literal of [HTTP request options](#http-request-options) that will be merged with every request.
|
|
2005
|
+
2. `beforeRequest` - [middleware](#using-http-middleware) that mutates every request before it is sent.
|
|
2006
|
+
3. `afterResponse` - [middleware](#using-http-middleware) that mutates every response before it is completed.
|
|
1990
2007
|
|
|
1991
2008
|
> Note: you can install any HTTP client you like - but this is greatly discouraged as you lose [automatic HTTP logging](#http-logging) and middleware.
|
|
1992
2009
|
|
|
1993
2010
|
### Shorthand HTTP Requests
|
|
1994
2011
|
|
|
1995
|
-
For simple HTTP requests that do not require special pre or post
|
|
2012
|
+
For simple HTTP requests that do not require special pre- or post-processing, you can specify the [HTTP request options](#http-request-options) as an object literal in your app definition.
|
|
1996
2013
|
|
|
1997
2014
|
This features:
|
|
1998
2015
|
|
|
@@ -2002,8 +2019,8 @@ This features:
|
|
|
2002
2019
|
|
|
2003
2020
|
```js
|
|
2004
2021
|
const triggerShorthandRequest = {
|
|
2005
|
-
method: 'GET',
|
|
2006
2022
|
url: 'https://{{bundle.authData.subdomain}}.example.com/v2/api/recipes.json',
|
|
2023
|
+
method: 'GET',
|
|
2007
2024
|
params: {
|
|
2008
2025
|
sort_by: 'id',
|
|
2009
2026
|
sort_order: 'DESC',
|
|
@@ -2025,28 +2042,36 @@ const App = {
|
|
|
2025
2042
|
|
|
2026
2043
|
```
|
|
2027
2044
|
|
|
2028
|
-
In the URL above, `{{bundle.authData.subdomain}}` is automatically replaced with the live value from the bundle. If the call returns a non 2xx return code, an error is automatically raised. The response body is automatically parsed as JSON and returned.
|
|
2045
|
+
In the URL above, `{{bundle.authData.subdomain}}` is automatically replaced with the live value from the bundle. If the call returns a non 2xx return code, an error is automatically raised. The response body is automatically parsed as JSON or form-encoded and returned.
|
|
2029
2046
|
|
|
2030
2047
|
An error will be raised if the response cannot be parsed as JSON or form-encoded. To use shorthand requests with other response types, add [middleware](#using-http-middleware) that sets `response.data` to the parsed response.
|
|
2031
2048
|
|
|
2032
2049
|
### Manual HTTP Requests
|
|
2033
2050
|
|
|
2034
|
-
|
|
2051
|
+
Use this when you need full control over the request/response. For example:
|
|
2035
2052
|
|
|
2036
|
-
To
|
|
2053
|
+
1. To do processing (usually involving [`bundle.inputData`](#bundleinputdata)) before a request is made
|
|
2054
|
+
2. To do processing of an API's response before you return data to Zapier
|
|
2055
|
+
3. To process an unusual response type, such as XML
|
|
2056
|
+
|
|
2057
|
+
To make a manual request, pass your [request options](#http-request-options) to `z.request()` then use the resulting [response object](#http-response-object) to return the data you want:
|
|
2037
2058
|
|
|
2038
2059
|
```js
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2060
|
+
const listRecipes = async (z, bundle) => {
|
|
2061
|
+
// Custom processing of bundle.inputData would go here...
|
|
2062
|
+
|
|
2063
|
+
const httpRequestOptions = {
|
|
2064
|
+
url: 'https://{{bundle.authData.subdomain}}.example.com/v2/api/recipes.json',
|
|
2065
|
+
method: 'GET',
|
|
2066
|
+
params: {
|
|
2067
|
+
cuisine: bundle.inputData.cuisine,
|
|
2044
2068
|
},
|
|
2045
2069
|
};
|
|
2046
|
-
const response = await z.request(
|
|
2070
|
+
const response = await z.request(httpRequestOptions);
|
|
2071
|
+
const recipes = response.data;
|
|
2072
|
+
|
|
2073
|
+
// Custom processing of recipes would go here...
|
|
2047
2074
|
|
|
2048
|
-
const recipes = response.data; // or response.json if you're using core v9 or older
|
|
2049
|
-
// You can do any custom processing of recipes here...
|
|
2050
2075
|
return recipes;
|
|
2051
2076
|
};
|
|
2052
2077
|
|
|
@@ -2057,7 +2082,7 @@ const App = {
|
|
|
2057
2082
|
// ...
|
|
2058
2083
|
operation: {
|
|
2059
2084
|
// ...
|
|
2060
|
-
perform:
|
|
2085
|
+
perform: listRecipes,
|
|
2061
2086
|
},
|
|
2062
2087
|
},
|
|
2063
2088
|
},
|
|
@@ -2065,6 +2090,8 @@ const App = {
|
|
|
2065
2090
|
|
|
2066
2091
|
```
|
|
2067
2092
|
|
|
2093
|
+
Manual requests perform lazy `{{curly}}` replacement. In the URL above, `{{bundle.authData.subdomain}}` is automatically replaced with the live value from the bundle.
|
|
2094
|
+
|
|
2068
2095
|
#### POST and PUT Requests
|
|
2069
2096
|
|
|
2070
2097
|
To POST or PUT data to your API you can do this:
|
|
@@ -2113,11 +2140,9 @@ const App = {
|
|
|
2113
2140
|
|
|
2114
2141
|
### Using HTTP middleware
|
|
2115
2142
|
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
> Example App: check out https://github.com/zapier/zapier-platform/tree/master/example-apps/middleware for a working example app using HTTP middleware.
|
|
2143
|
+
To process all HTTP requests in a certain way, use the `beforeRequest` and `afterResponse` middleware functions.
|
|
2119
2144
|
|
|
2120
|
-
|
|
2145
|
+
Middleware functions go in your app definition:
|
|
2121
2146
|
|
|
2122
2147
|
```js
|
|
2123
2148
|
const addHeader = (request, z, bundle) => {
|
|
@@ -2174,6 +2199,8 @@ Here is the full request lifecycle when you call `z.request({...})`:
|
|
|
2174
2199
|
|
|
2175
2200
|
The resulting response object is returned from `z.request()`.
|
|
2176
2201
|
|
|
2202
|
+
> Example App: check out https://github.com/zapier/zapier-platform/tree/master/example-apps/middleware for a working example app using HTTP middleware.
|
|
2203
|
+
|
|
2177
2204
|
#### Error Response Handling
|
|
2178
2205
|
|
|
2179
2206
|
Since `v10.0.0`, `z.request()` calls `response.throwForStatus()` before it returns a response. You can disable automatic error throwing by setting `skipThrowForStatus` on the request object:
|
|
@@ -2186,7 +2213,7 @@ const perform = async (z, bundle) => {
|
|
|
2186
2213
|
skipThrowForStatus: true
|
|
2187
2214
|
});
|
|
2188
2215
|
// Now you handle error response on your own.
|
|
2189
|
-
// The following is equivalent to response.throwForStatus(),
|
|
2216
|
+
// The following is equivalent to response.throwForStatus(),
|
|
2190
2217
|
// but you have to remember to do it on every request
|
|
2191
2218
|
if (response.status >= 400) {
|
|
2192
2219
|
throw new z.errors.ResponseError(response);
|
|
@@ -2219,13 +2246,13 @@ This behavior has changed periodically across major versions, which changes how/
|
|
|
2219
2246
|
|
|
2220
2247
|

|
|
2221
2248
|
|
|
2222
|
-
Ensure you're handling errors correctly for your platform version. The latest released version is **12.0
|
|
2249
|
+
Ensure you're handling errors correctly for your platform version. The latest released version is **12.1.0**.
|
|
2223
2250
|
|
|
2224
2251
|
### HTTP Request Options
|
|
2225
2252
|
|
|
2226
|
-
Shorthand requests and manual
|
|
2253
|
+
[Shorthand requests](#shorthand-http-requests) and [manual requests](#manual-http-requests) support the following HTTP `options`:
|
|
2227
2254
|
|
|
2228
|
-
* `url`: HTTP url, you can provide it
|
|
2255
|
+
* `url`: HTTP url, you can provide it as a separate argument (`z.request(url, options)`) or as part of the `options` object (`z.request({url: url, ...})`).
|
|
2229
2256
|
* `method`: HTTP method, default is `GET`.
|
|
2230
2257
|
* `headers`: request headers object, format `{'header-key': 'header-value'}`.
|
|
2231
2258
|
* `params`: URL query params object, format `{'query-key': 'query-value'}`.
|
|
@@ -2286,7 +2313,7 @@ const response = await z.request({
|
|
|
2286
2313
|
// options
|
|
2287
2314
|
});
|
|
2288
2315
|
|
|
2289
|
-
// A bunch of examples
|
|
2316
|
+
// A bunch of examples for demonstration
|
|
2290
2317
|
response.status;
|
|
2291
2318
|
response.headers['Content-Type'];
|
|
2292
2319
|
response.getHeader('content-type');
|
|
@@ -2502,7 +2529,7 @@ module.exports = App;
|
|
|
2502
2529
|
|
|
2503
2530
|
```
|
|
2504
2531
|
|
|
2505
|
-
>
|
|
2532
|
+
> To create a new integration for handling files, run `zapier init [your app name] --template files`. You can also check out our working example app [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/files).
|
|
2506
2533
|
|
|
2507
2534
|
|
|
2508
2535
|
## Logging
|
|
@@ -2661,7 +2688,7 @@ delay in seconds:
|
|
|
2661
2688
|
```js
|
|
2662
2689
|
const yourAfterResponse = (resp) => {
|
|
2663
2690
|
if (resp.status === 429) {
|
|
2664
|
-
throw new ThrottledError('message here', 60); // Zapier will retry in 60 seconds
|
|
2691
|
+
throw new z.errors.ThrottledError('message here', 60); // Zapier will retry in 60 seconds
|
|
2665
2692
|
}
|
|
2666
2693
|
return resp;
|
|
2667
2694
|
};
|
|
@@ -2669,14 +2696,14 @@ const yourAfterResponse = (resp) => {
|
|
|
2669
2696
|
|
|
2670
2697
|
## Testing
|
|
2671
2698
|
|
|
2672
|
-
You can write unit tests for your Zapier
|
|
2699
|
+
You can write unit tests for your Zapier integration that run locally, outside of the Zapier editor.
|
|
2673
2700
|
You can run these tests in a CI tool like [Travis](https://travis-ci.com/).
|
|
2674
2701
|
|
|
2675
2702
|
### Writing Unit Tests
|
|
2676
2703
|
|
|
2677
|
-
|
|
2704
|
+
From v10 of `zapier-platform-cli`, we recommend using the [Jest](https://jestjs.io/) testing framework. After running `zapier init` you should find an example test to start from in the `test` directory.
|
|
2678
2705
|
|
|
2679
|
-
> Note: On v9, the recommendation was [Mocha](https://mochajs.org/). You can still use
|
|
2706
|
+
> Note: On v9, the recommendation was [Mocha](https://mochajs.org/). You can still use Mocha if you prefer.
|
|
2680
2707
|
|
|
2681
2708
|
```js
|
|
2682
2709
|
/* globals describe, expect, test */
|
|
@@ -2693,7 +2720,7 @@ const appTester = zapier.createAppTester(App);
|
|
|
2693
2720
|
zapier.tools.env.inject();
|
|
2694
2721
|
|
|
2695
2722
|
describe('triggers', () => {
|
|
2696
|
-
test('
|
|
2723
|
+
test('new recipe', async () => {
|
|
2697
2724
|
const bundle = {
|
|
2698
2725
|
inputData: {
|
|
2699
2726
|
style: 'mediterranean',
|
|
@@ -2701,7 +2728,7 @@ describe('triggers', () => {
|
|
|
2701
2728
|
};
|
|
2702
2729
|
|
|
2703
2730
|
const results = await appTester(
|
|
2704
|
-
App.triggers.
|
|
2731
|
+
App.triggers.recipe.operation.perform,
|
|
2705
2732
|
bundle
|
|
2706
2733
|
);
|
|
2707
2734
|
expect(results.length).toBeGreaterThan(1);
|
|
@@ -2727,8 +2754,8 @@ const App = require('../index');
|
|
|
2727
2754
|
const appTester = zapier.createAppTester(App);
|
|
2728
2755
|
|
|
2729
2756
|
describe('triggers', () => {
|
|
2730
|
-
test('
|
|
2731
|
-
const
|
|
2757
|
+
test('new recipe', async () => {
|
|
2758
|
+
const adHocResult = await appTester(
|
|
2732
2759
|
// your in-line function takes the same [z, bundle] arguments as normal
|
|
2733
2760
|
async (z, bundle) => {
|
|
2734
2761
|
// requests are made using your integration's actual middleware
|
|
@@ -2759,8 +2786,8 @@ describe('triggers', () => {
|
|
|
2759
2786
|
}
|
|
2760
2787
|
);
|
|
2761
2788
|
|
|
2762
|
-
expect(
|
|
2763
|
-
expect(
|
|
2789
|
+
expect(adHocResult.someHash).toEqual('a5beb6624e092adf7be31176c3079e64');
|
|
2790
|
+
expect(adHocResult.data).toEqual({ whatever: true });
|
|
2764
2791
|
|
|
2765
2792
|
// ... rest of test
|
|
2766
2793
|
});
|
|
@@ -2770,7 +2797,7 @@ describe('triggers', () => {
|
|
|
2770
2797
|
|
|
2771
2798
|
### Mocking Requests
|
|
2772
2799
|
|
|
2773
|
-
|
|
2800
|
+
It's useful to test your code without actually hitting any external services. [Nock](https://github.com/node-nock/nock) is a Node.js utility that intercepts requests before they ever leave your computer. You can specify a response code, body, headers, and more. It works out of the box with `z.request` by setting up your `nock` before calling `appTester`.
|
|
2774
2801
|
|
|
2775
2802
|
```js
|
|
2776
2803
|
/* globals describe, expect, test */
|
|
@@ -2783,7 +2810,7 @@ const appTester = zapier.createAppTester(App);
|
|
|
2783
2810
|
const nock = require('nock');
|
|
2784
2811
|
|
|
2785
2812
|
describe('triggers', () => {
|
|
2786
|
-
test('
|
|
2813
|
+
test('new recipe', async () => {
|
|
2787
2814
|
const bundle = {
|
|
2788
2815
|
inputData: {
|
|
2789
2816
|
style: 'mediterranean',
|
|
@@ -2814,7 +2841,7 @@ describe('triggers', () => {
|
|
|
2814
2841
|
|
|
2815
2842
|
```
|
|
2816
2843
|
|
|
2817
|
-
|
|
2844
|
+
Here's more info about nock and its usage in the [README](https://github.com/node-nock/nock/blob/master/README.md).
|
|
2818
2845
|
|
|
2819
2846
|
### Running Unit Tests
|
|
2820
2847
|
|
|
@@ -2857,11 +2884,11 @@ zapier test
|
|
|
2857
2884
|
|
|
2858
2885
|
### Testing in Your CI
|
|
2859
2886
|
|
|
2860
|
-
Whether you use Travis, Circle, Jenkins, or
|
|
2887
|
+
Whether you use Travis, Circle, Jenkins, or another service, we aim to make it painless to test in an automated environment.
|
|
2861
2888
|
|
|
2862
|
-
Behind the scenes `zapier test`
|
|
2889
|
+
Behind the scenes `zapier test` does a standard `npm test`, which could be [Jest](https://jestjs.io/) or [Mocha](https://mochajs.org/), based on your project setup.
|
|
2863
2890
|
|
|
2864
|
-
This makes it
|
|
2891
|
+
This makes it straightforward to integrate into your testing interface. For example, if you want to test with [Travis CI](https://travis-ci.com/), the `.travis.yml` would look something like this:
|
|
2865
2892
|
|
|
2866
2893
|
```yaml
|
|
2867
2894
|
language: node_js
|
|
@@ -2871,13 +2898,13 @@ before_script: npm install -g zapier-platform-cli
|
|
|
2871
2898
|
script: CLIENT_ID=1234 CLIENT_SECRET=abcd zapier test
|
|
2872
2899
|
```
|
|
2873
2900
|
|
|
2874
|
-
You can substitute `zapier test` with `npm test`, or a direct call to `node_modules/.bin/jest`.
|
|
2901
|
+
You can substitute `zapier test` with `npm test`, or a direct call to `node_modules/.bin/jest`. We recommend putting environment variables directly into the configuration screens Jenkins, Travis, or other services provide.
|
|
2875
2902
|
|
|
2876
|
-
|
|
2903
|
+
Alternatively to reading the deploy key from root (the default location), you may set the `ZAPIER_DEPLOY_KEY` environment variable to run privileged commands without the human input needed for `zapier login`. We suggest encrypting your deploy key in the manner your CI provides (such as [these instructions](https://docs.travis-ci.com/user/environment-variables/#Defining-encrypted-variables-in-.travis.yml), for Travis).
|
|
2877
2904
|
|
|
2878
2905
|
### Debugging Tests
|
|
2879
2906
|
|
|
2880
|
-
Sometimes tests aren't enough and you may want to step through your code and set breakpoints. The testing suite is a regular Node.js process, so debugging it doesn't take anything special. Because we recommend `jest` for testing, these instructions will outline steps for debugging w/ jest, but other test runners will work similarly. You can also refer to [Jest's own docs on the subject](https://jestjs.io/docs/en/troubleshooting#tests-are-failing-and-you-dont-know-why).
|
|
2907
|
+
Sometimes tests aren't enough, and you may want to step through your code and set breakpoints. The testing suite is a regular Node.js process, so debugging it doesn't take anything special. Because we recommend `jest` for testing, these instructions will outline steps for debugging w/ jest, but other test runners will work similarly. You can also refer to [Jest's own docs on the subject](https://jestjs.io/docs/en/troubleshooting#tests-are-failing-and-you-dont-know-why).
|
|
2881
2908
|
|
|
2882
2909
|
To start, add the following line to the `scripts` section of your `package.json`:
|
|
2883
2910
|
|
|
@@ -2928,7 +2955,7 @@ After a few seconds, you'll see your code, the `debugger` statement, and info ab
|
|
|
2928
2955
|
|
|
2929
2956
|

|
|
2930
2957
|
|
|
2931
|
-
|
|
2958
|
+
Debugging combined with thorough unit tests will hopefully equip you in keeping your Zapier integration in smooth working order.
|
|
2932
2959
|
|
|
2933
2960
|
## Using `npm` Modules
|
|
2934
2961
|
|
|
@@ -3049,7 +3076,7 @@ zapier push
|
|
|
3049
3076
|
|
|
3050
3077
|
There are a lot of details left out - check out the full example app for a working setup.
|
|
3051
3078
|
|
|
3052
|
-
>
|
|
3079
|
+
> To create a new integration with Babel, run `zapier init [your app name] --template babel`. You can also check out our working example app [here](https://github.com/zapier/zapier-platform/tree/master/example-apps/babel).
|
|
3053
3080
|
|
|
3054
3081
|
## FAQs
|
|
3055
3082
|
|
|
@@ -3083,7 +3110,7 @@ Not natively, but it can! Users have reported that the following `npm` modules a
|
|
|
3083
3110
|
* [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js)
|
|
3084
3111
|
* [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser)
|
|
3085
3112
|
|
|
3086
|
-
Since core v10, it's possible for [shorthand requests](shorthand-http-requests) to parse XML. Use an `afterResponse` [middleware](using-http-middleware) that sets `response.data` to the parsed XML:
|
|
3113
|
+
Since core v10, it's possible for [shorthand requests](#shorthand-http-requests) to parse XML. Use an `afterResponse` [middleware](#using-http-middleware) that sets `response.data` to the parsed XML:
|
|
3087
3114
|
|
|
3088
3115
|
```js
|
|
3089
3116
|
const xml = require('pixl-xml');
|
|
@@ -3205,7 +3232,7 @@ To understand search-powered fields, we have to have a good understanding of dyn
|
|
|
3205
3232
|
|
|
3206
3233
|
When users are selecting specific resources (for instance, a Google Sheet), it's important they're able to select the exact sheet they want. Instead of referencing the sheet by name (which may change), we match via `id` instead. Rather than directing the user copy and paste an id for every item they might encounter, there is the notion of a **dynamic dropdown**. A dropdown is a trigger that returns a list of resources. It can pull double duty and use its results to power another trigger, search, or action in the same app. It provides a list of ids with labels that show the item's name:
|
|
3207
3234
|
|
|
3208
|
-

|
|
3209
3236
|
|
|
3210
3237
|
The field's value reaches your app as an id. You define this connection with the `dynamic` property, which is a string: `trigger_key.id_key.label_key`. This approach works great if the user setting up the Zap always wants the Zap to use the same spreadsheet. They specify the id during setup and the Zap runs happily.
|
|
3211
3238
|
|
|
@@ -3218,7 +3245,7 @@ The field's value reaches your app as an id. You define this connection with the
|
|
|
3218
3245
|
|
|
3219
3246
|
If the connection between steps 3 and 4 is a common one, you can indicate that in your field by specifying `search` as a `search_key.id_key`. When paired **with a dynamic dropdown**, this will add a button to the editor that will add the search step to the user's Zap and map the id field correctly.
|
|
3220
3247
|
|
|
3221
|
-

|
|
3222
3249
|
|
|
3223
3250
|
This is paired most often with "update" actions, where a required parameter will be a resource id.
|
|
3224
3251
|
|
|
@@ -3404,7 +3431,7 @@ Broadly speaking, all releases will continue to work indefinitely. While you nev
|
|
|
3404
3431
|
For more info about which Node versions are supported, see [the faq](#how-do-i-manually-set-the-nodejs-version-to-run-my-app-with).
|
|
3405
3432
|
|
|
3406
3433
|
<!-- TODO: if we decouple releases, change this -->
|
|
3407
|
-
The most recently released version of `cli` and `core` is **12.0
|
|
3434
|
+
The most recently released version of `cli` and `core` is **12.1.0**. You can see the versions you're working with by running `zapier -v`.
|
|
3408
3435
|
|
|
3409
3436
|
To update `cli`, run `npm install -g zapier-platform-cli`.
|
|
3410
3437
|
|
|
@@ -3420,4 +3447,4 @@ You can get help by either emailing `partners@zapier.com` or by [joining our dev
|
|
|
3420
3447
|
|
|
3421
3448
|
## Developing on the CLI
|
|
3422
3449
|
|
|
3423
|
-
|
|
3450
|
+
See [CONTRIBUTING.md](https://github.com/zapier/zapier-platform/blob/master/CONTRIBUTING.md).
|