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.md CHANGED
@@ -1,9 +1,13 @@
1
1
  <!-- GENERATED! ONLY EDIT `README-source.md` -->
2
2
 
3
3
  <h1 align="center">
4
- <a href="https://zapier.com"><img src="https://raw.githubusercontent.com/zapier/zapier-platform/master/packages/cli/goodies/zapier-logomark.png" alt="Zapier" width="200"></a>
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
- Zapier Platform CLI
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.2**), as of this writing. If you're using an older version of the CLI, you may want to check out these historical releases:
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/minimal/.travis.yml) file in our template apps to get you started.
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: there are plenty of templates & example apps to choose from! [View all Example Apps here.](#example-apps).
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 - and Zapier provides a handful of methods for helping your users authenticate with your application. Zapier will provide some of the core behaviors, but you'll likely need to handle the rest.
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
- > Hint: You can access the data tied to your authentication via the `bundle.authData` property in any method called in your app. Exceptions exist in OAuth and Session auth. Please see them below.
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/basic-auth for a working example app for basic auth.
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 will provide Zapier their username and password and Zapier will handle all the nonce and quality of protection details automatically.
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/digest-auth for a working example app for digest auth.
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 sends an additional request beforehand to get the server nonce.
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
- This is what most "API Key" driven apps should default to using. You'll likely provide some custom `beforeRequest` middleware or a `requestTemplate` to complete the authentication by adding/computing needed headers.
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/custom-auth for a working example app for custom auth.
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
- Probably the most "powerful" mechanism for authentication - it gives you the ability to exchange some user provided data for some authentication data (IE: username & password for a session key).
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/session-auth for a working example app for session auth.
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
- > Note: For Session auth, `authentication.sessionConfig.perform` will have the provided fields in `bundle.inputData` instead of `bundle.authData` because `bundle.authData` will only have "previously existing" values, which will be empty the first time the Zap runs.
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's](https://developer.twitter.com/en/docs/basics/authentication/overview) and [Trello's](https://developers.trello.com/page/authorization) implementation of the 3-legged OAuth flow.
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
- > Example Apps: 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.
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
- > Note: For OAuth1, `authentication.oauth1Config.getRequestToken`, `authentication.oauth1Config.authorizeUrl`, and `authentication.oauth1Config.getAccessToken` will have the provided fields in `bundle.inputData` instead of `bundle.authData` because `bundle.authData` will only have "previously existing" values, which will be empty when the user hasn't connected their account on your service to Zapier. Also note that `authentication.oauth1Config.getAccessToken` has access to the users return values in `rawRequest` and `cleanedRequest` should you need to extract other values (for example from the query string).
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/oauth2 for a working example app for OAuth2.
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
- > Note: For OAuth2, `authentication.oauth2Config.authorizeUrl`, `authentication.oauth2Config.getAccessToken`, and `authentication.oauth2Config.refreshAccessToken` will have the provided fields in `bundle.inputData` instead of `bundle.authData` because `bundle.authData` will only have "previously existing" values, which will be empty when the user hasn't connected their account on your service to Zapier. Also note that `authentication.oauth2Config.getAccessToken` has access to the users return values in `rawRequest` and `cleanedRequest` should you need to extract other values (for example from the query string).
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/resource for a working example app using resources.
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/trigger for a working example app using triggers.
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
- ![gif of setting up an action field in Zap Editor](https://cdn.zapier.com/storage/photos/6bd938f7cad7e34c75ba1c1d3be75ac5.gif)
1054
+ ![gif of setting up an action field in Zap Editor](https://cdn.zappy.app/52721a3cb202446b7c298e303b710471.gif)
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, it might be necessary to provide fields that are dynamically generated - especially for custom fields. This is a common pattern for CRMs, form software, databases and more. Basically - you can provide a function instead of a field and we'll evaluate that function - merging the dynamic fields with the static fields.
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 reponse.throwForStatus() if you're using core v9 or older
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` property. This informs the Zapier UI that whenever the value of that field changes, fields need to be recomputed. An example could be a static dropdown of "dessert type" that will change whether the function that generates dynamic fields includes a field "with sprinkles." If your field affects others, this is an important property to set.
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 Fields button is used on the trigger or action.
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
- ![screenshot of dynamic dropdown in Zap Editor](https://cdn.zapier.com/storage/photos/dd31fa761e0cf9d0abc9b50438f95210.png)
1236
+ ![screenshot of dynamic dropdown in Zap Editor](https://cdn.zappy.app/6a90fcc532704f6c14b91586f5cd1d5b.png)
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`. For example:
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 primary ways to make HTTP requests in the Zapier platform:
1997
+ There are two ways to make HTTP requests:
1981
1998
 
1982
- 1. **Shorthand HTTP Requests** - these are simple object literals that make it easy to define simple requests.
1983
- 2. **Manual HTTP Requests** - you use `z.request([url], options)` to make the requests and control the response. Use this when you need to change options for certain requests (for all requests, use middleware).
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
- There are also a few helper constructs you can use to reduce boilerplate:
2002
+ Use these helper constructs to reduce boilerplate:
1986
2003
 
1987
- 1. `requestTemplate` which is an shorthand HTTP request that will be merged with every request.
1988
- 2. `beforeRequest` middleware which is an array of functions to mutate a request before it is sent.
1989
- 3. `afterResponse` middleware which is an array of functions to mutate a response before it is completed.
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 processing, you can specify the HTTP options as an object literal in your app definition.
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
- When you need to do custom processing of the response, or need to process non-JSON responses, you can make manual HTTP requests. This approach does not perform any magic - no status code checking, no automatic JSON parsing. Use this method when you need more control. Manual requests do perform lazy `{{curly}}` replacement.
2051
+ Use this when you need full control over the request/response. For example:
2035
2052
 
2036
- To make a manual HTTP request, use the `request` method of the `z` object:
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 listExample = async (z, bundle) => {
2040
- const customHttpOptions = {
2041
- url: 'https://example.com/api/v2/recipes.json',
2042
- headers: {
2043
- 'my-header': 'from zapier',
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(customHttpOptions);
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: listExample,
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
- If you need to process all HTTP requests in a certain way, you may be able to use one of utility HTTP middleware functions.
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
- Try putting them in your app definition:
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
  ![](https://cdn.zappy.app/e835d9beca1b6489a065d51a381613f3.png)
2221
2248
 
2222
- Ensure you're handling errors correctly for your platform version. The latest released version is **12.0.2**.
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 `z.request([url], options)` calls support the following HTTP `options`:
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 both `z.request(url, options)` or `z.request({url: url, ...})`.
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 lines for cherry picking
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
- > Example App: check out https://github.com/zapier/zapier-platform/tree/master/example-apps/files for a working example app using files.
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 app that run locally, outside of the Zapier editor.
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
- Since v10, 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.
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 it if you prefer Mocha.
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('load recipes', async () => {
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.species.operation.perform,
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('load recipes', async () => {
2731
- const adHodResult = await appTester(
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(adHodResult.someHash).toEqual('a5beb6624e092adf7be31176c3079e64');
2763
- expect(adHodResult.data).toEqual({ whatever: true });
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
- While testing, 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`.
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('load recipes', async () => {
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
- There's more info about nock and its usage in its [readme](https://github.com/node-nock/nock/blob/master/README.md).
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 anything else, we aim to make it painless to test in an automated environment.
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` is doing a pretty standard `npm test`, which could be [Jest](https://jestjs.io/) or [Mocha](https://mochajs.org/), based on your project setup.
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 pretty straightforward to integrate into your testing interface. If you'd like to test with [Travis CI](https://travis-ci.com/) for example - the `.travis.yml` would look something like this:
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`. Also, we generally recommend putting the environment variables into whatever configuration screen Jenkins or Travis provides!
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
- As an alternative 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 whatever manner you CI provides (such as [these instructions](https://docs.travis-ci.com/user/environment-variables/#Defining-encrypted-variables-in-.travis.yml), for Travis).
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
  ![](https://cdn.zappy.app/4bfdfe079a344ab7aced64ad7728bc6a.png)
2930
2957
 
2931
- Using debugging in combination with thorough unit tests, you will hopefully be able to keep your Zapier integration in smooth working order.
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
- > Example App: Check out https://github.com/zapier/zapier-platform/tree/master/example-apps/babel for a working example app using Babel.
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
- ![](https://cdn.zapier.com/storage/photos/fb56bdc2aab91504be0e51800bec4d64.png)
3235
+ ![](https://cdn.zappy.app/2d7eeda63ff34b70f1d1788de0117181.png)
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
- ![](https://cdn.zapier.com/storage/photos/d263fd3a56cf8108cb89195163e7c9aa.png)
3248
+ ![](https://cdn.zappy.app/081e63141ff05c131dadb8ebbea727b0.png)
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.2**. You can see the versions you're working with by running `zapier -v`.
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
- For Zapier employees, see [this quip doc](https://zapier.quip.com/bns4AxqwaMIm/Working-on-the-CLI-Platform-CoreSchemaCLI) for info about creating releases.
3450
+ See [CONTRIBUTING.md](https://github.com/zapier/zapier-platform/blob/master/CONTRIBUTING.md).