- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在考虑创建一个“Zap 应用程序”,并且想知道是否有人使用新的 .Net Webhooks 这样做了。他们似乎具有 RESTHooks 所要求的“模式”,即订阅/发布机制。它工作的例子并不多,我想在我花了几天时间实现它并发现它不兼容之前进行检查。
Hook 到 Zapier 的实际代码示例会很棒!
最佳答案
进行了一些研究,但我终于让 Zapier Rest Hooks 工作了。并不像我希望的那样直接(更有可能是我的吸收速度有点慢)。客户支持非常出色且友好,因此请不要犹豫,将您的问题通过电子邮件发送给他们。此外,一旦您开始使用它,它就会非常强大,尽管它们的正常 webhook 机制也可以工作并且不需要您创建 Zap 应用程序。在撰写本文时,我还没有推出该应用程序,尽管它正在本地运行。这假设您已经开始在开发人员仪表板中创建自己的 Zapier 应用程序。这很简单,所以我不会在这里介绍。
此解释仅涵盖创建单个触发器(尽管您创建了 1 个更私有(private)的触发器以支持用户身份验证,而我创建了另一个用于动态下拉目的)并且仅作为具有基本身份验证的 RESThook。基础知识是:
1. 创建网络钩子(Hook) 允许 Zapier 添加、更新和删除对您的操作的订阅。通过“订阅” Zapier 不必轮询您的 webhook,而是当订阅的操作发生在您这边时,您响应 Zapier 在订阅过程中提供给您的 URL。
2. 创建数据库表 记录这些订阅,存储您需要的数据,然后当您这边触发操作时,将响应发布回 Zapier 提供的 URL。
3. 当 Action 被触发时,识别并发布数据 你告诉zapier你会发送。 Zapier 非常聪明,它会为您映射数据(JSON 或 XML),因此当连接到另一个应用程序时,用户可以在两者之间进行映射。
所以还有一些细节。这是在 .Net 上的 C# 中完成的,但我认为这些概念在任何其他语言或平台中都应该同样适用。
首先是 RESTHook。下面是 RESTHook 方法的示例。请注意,我花了几天时间试图弄清楚 Zapier 脚本方面,所以我对命名约定并不完全满意,但希望您能理解。
在这种情况下,有一个“表单”的概念,它是一块 JSON 保存我关心的数据,用户所属的用户和帐户。它们在系统中都有一个唯一的 ID。最后订阅本身有一个 id。当您订阅时,特定帐户中的特定用户正在订阅特定的表单,当特定的触发器(提交该表单)完成时,将发送给 Zapier。
REST钩子(Hook):
先是RouteConfig
它将路径映射到要执行的方法。你可以看到我实现的所有方法。其中一些未使用,只是为了将来可能使用(例如更新订阅)而包含在内。
// ZAPIER Webhooks
routes.MapRoute(
"User_Form_List",
"api/zapier/user/formlist",
new { controller = "Zapier", action = "RetrieveFormListForUser" },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"Authenticate_Subscription",
"api/zapier/authenticate",
new { controller = "Zapier", action = "WebhookAuthenticate" },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"Test_Subscription",
"api/zapier/subscription/testdata",
new { controller = "Zapier", action = "TestData" },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"Create_Submission",
"api/zapier/subscription/create",
new { controller = "Zapier", action = "CreateSubscription" },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"List_Subscriptions",
"api/zapier/subscription",
new { controller = "Zapier", action = "ListSubscriptions" },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"Get_Subscriptions",
"api/zapier/subscription/{id}",
new { controller = "Zapier", action = "GetSubscription", id = 0 },
new { httpMethod = new HttpMethodConstraint("GET") }
);
routes.MapRoute(
"Update_Subscription",
"api/zapier/subscription/{id}",
new { controller = "Zapier", action = "UpdateSubscription", id = 0 },
new { httpMethod = new HttpMethodConstraint("PUT") }
);
routes.MapRoute(
"Delete_Subscription",
"api/zapier/subscription/{id}",
new { controller = "Zapier", action = "DeleteSubscription", id = 0 },
new { httpMethod = new HttpMethodConstraint("DELETE") }
);
public class ZapierController : BaseController //(this inherits from Controller)
{
private readonly IMyRepository _DBrepository;
public ZapierController(IMyRepository repository, ...lots of other autowiring you don't need or care about)
: base(logger)
{
_DBrepository = repository;
}
#region Zapier Subscriptions
// api/zapier/subscription/create : Creates a subscription
[HttpGet]
public ActionResult CreateSubscription()
{
ApiResult authresult = Authenticate();
if (authresult.code != 201)
{
return JsonApiResult(authresult);
}
// Get the request parameters
var reqParams = GetParameters();
// Create the subscription so long as it does not already exist
WebhookSubscription sub = new WebhookSubscription();
// _currentUser and _currentAccount are set as part of the authenticate and stored in our base controller
sub.AccountId = _currentAccount.Id;
sub.UserId = _currentUser.UserId;
sub.TargetURL = reqParams["target_url"];
sub.EventType = reqParams["target_event"];
sub.FormId = Int32.Parse(reqParams["form_id"]);
sub.IsActive = true;
ObjectResult workflowActionRecord = _DBrepository.createWebhookSubscription(sub);
sub.Id = workflowActionRecord.objectId;
// return the subscription back to Zapier in the result. Zapier will remember it
var result = new ApiResult();
result.data.id = workflowActionRecord.objectId;
result.data.subscription = sub;
result.code = 201;
return JsonApiResult(result);
}
// api/zapier/authenticate : used to test authentication
[HttpGet]
public ActionResult WebhookAuthenticate()
{
ApiResult authresult = Authenticate();
var result = new ApiResult();
result.code = 201;
return JsonApiResult(result);
}
// api/zapier/user/formlist : returns list of forms for this user
[HttpGet]
public ActionResult RetrieveFormListForUser()
{
ApiResult authresult = Authenticate();
var result = new ApiResult();
List<Form> forms = _DBRepository.FormListRetrieveByUser(_currentUser, false);
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new JavaScriptDateTimeConverter());
serializer.NullValueHandling = NullValueHandling.Ignore;
// Again Zapier likes arrays returned
JArray objarray = JArray.FromObject(forms);
return JsonApiResultDynamic(objarray);
}
// api/zapier/subscription/testdata : returns test data for zapier
[HttpGet]
public ActionResult TestData()
{
ApiResult authresult = Authenticate();
var result = new ApiResult();
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new JavaScriptDateTimeConverter());
serializer.NullValueHandling = NullValueHandling.Ignore;
// Get the request parameters
var reqParams = GetParameters();
int chosenFormId = -1;
// We need the form Id to proceed
if (reqParams != null && reqParams["form_id"] != null)
chosenFormId = Int32.Parse(reqParams["form_id"]);
else
return JsonApiResult(new ApiResult() { code = 403, error = "Form Id Not Found" });
// Get the form by Form Id, and return the JSON...I have removed that code, but make sure the result is place in an Array
var resultdata = new[] { myFinalFormJSON };
JArray objarray = JArray.FromObject(resultdata);
return JsonApiResultDynamic(objarray);
}
// api/zapier/subscription : returns list of subscriptions by account
[HttpGet]
public ActionResult ListSubscriptions()
{
ApiResult authresult = Authenticate();
// Get a list all subscriptions for the account
List<WebhookSubscription> actionData = _DBrepository.accountWebhookSubscriptions(_currentAccount.Id);
var result = new ApiResult();
result.code = 201;
result.data.subscriptions = actionData;
return JsonApiResult(result);
}
// api/zapier/subscription/{id} : Creates a subscription
[HttpGet]
public ActionResult GetSubscription(int id)
{
ApiResult authresult = Authenticate();
// Get a list all subscriptions for the account
WebhookSubscription actionData = _DBrepository.getWebhookSubscription(id);
var result = new ApiResult();
result.data.subscription = actionData; ;
result.code = 201;
return JsonApiResult(result);
}
// api/zapier/subscription/{id} : updates a subscription
[HttpPut]
public ActionResult UpdateSubscription(int id)
{
ApiResult authresult = Authenticate();
// get target url and eventy type from the body of request
string jsonString = RequestBody();
var json = CommonUtils.DecodeJson(jsonString);
// Create the subscription so long as it does not already exist
WebhookSubscription sub = _DBrepository.getWebhookSubscription(id);
var result = new ApiResult();
if (sub != null)
{
sub.TargetURL = json.target_url; ;
sub.EventType = json.eventType;
ObjectResult objResult = _DBrepository.updateWebhookSubscription(sub);
result.code = 201;
}
return JsonApiResult(result);
}
// api/zapier/subscription/{id} : deletes a subscription
[HttpDelete]
public ActionResult DeleteSubscription(int id)
{
ApiResult authresult = Authenticate();
// Delete a subscription
_DBrepository.deleteWebhookSubscription(id);
var result = new ApiResult();
result.code = 201;
return JsonApiResult(result);
}
// We need to Basic Auth for each call to subscription
public ApiResult Authenticate()
{
// get auth from basic authentication header
var auth = this.BasicAuthHeaderValue();
// parse credentials from auth
var userCredentials = Encoding.UTF8.GetString(Convert.FromBase64String(auth));
var parts = CommonUtils.SplitOnFirst(userCredentials, ":");
var username = parts[0];
var password = parts[1];
// authenticate user against repository
if (!_DBrepository.UserAuthenticate(username, password))
{
_logger.Info("Invalid Authentication: " + username);
return new ApiResult() { code = 401, error = "invalid authentication" };
}
return new ApiResult() { code = 201, error = "successful authentication" };
}
}
Create.Table("WebhookSubscription")
.WithColumn("Id").AsInt32().Identity().PrimaryKey().NotNullable()
.WithColumn("AccountId").AsInt32().NotNullable()
.WithColumn("UserId").AsInt32().NotNullable()
.WithColumn("EventType").AsString(256).NotNullable()
.WithColumn("TargetURL").AsString(1000).NotNullable()
.WithColumn("IsActive").AsBoolean().NotNullable()
.WithColumn("CreatedOn").AsDateTime().Nullable()
.WithColumn("FormId").AsInt32().NotNullable().WithDefaultValue(0);
.WithColumn("UpdatedAt").AsDateTime().Nullable();
public BusinessResult FormSubmitted(string jsonString)
{
var json = CommonUtils.DecodeJson(jsonString);
var account = _DBrepository.AccountRetrieveById(_currentUser.AccountId.Value); // Assumes user has bee authenticated
// inject additional meta data into json and retrieve submission/alert settings
var form = _DBformRepository.FormRetrieveById((int)json.formId);
// Lookup Subscription Webhooks
List<WebhookSubscription> subscriptions = _DBrepository.accountWebhookSubscriptions(account.Id);
if (subscriptions != null && subscriptions.Count > 0)
{
foreach (WebhookSubscription sub in subscriptions)
{
if (sub.EventType.Equals("new_form_submission") && sub.FormId == form.Id)
{
_webhookService.NewFormSubmission(sub, jsonString, form.Name, account.Name, account.Id);
}
}
}
}
public class WebhookService : IWebhookService
{
protected readonly IRepository _DBrepository;
public WebhookService(IRepository repository)
{
_DBrepository = repository;
}
public void NewFormSubmission(string formResultJSON)
{
throw new NotImplementedException();
}
public void NewFormSubmission(WebhookSubscription subscription, string formResultJSON, string formName, string accountName, int accountId)
{
// Now post to webhook URL
string response;
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/json";
// Needs to be an array sent to Zapier
response = client.UploadString(subscription.TargetURL, "POST", "[" + formResultJSON + "]");
}
}
}
var Zap = {
pre_subscribe: function(bundle) {
bundle.request.method = 'GET';
bundle.request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
bundle.request.params = {
target_url: bundle.subscription_url,
target_event:bundle.event,
form_id:bundle.trigger_fields.form_id
};
bundle.request.data = $.param({
target_url: bundle.subscription_url,
target_event:bundle.event,
form_id:bundle.trigger_fields.form_id
});
return bundle.request;
},
post_subscribe: function(bundle) {
// must return a json serializable object for use in pre_unsubscribe
var data = JSON.parse(bundle.response.content);
// we need this in order to build the {{webhook_id}}
// in the rest hook unsubscribe url
return {webhook_id: data.id};
},
pre_unsubscribe: function(bundle) {
bundle.request.method = 'DELETE';
bundle.request.data = null;
return bundle.request;
},
new_form_submission_pre_poll: function(bundle) {
bundle.request.method = 'GET';
bundle.request.headers['Content-Type'] = 'application/x-www-form-urlencoded';
bundle.request.params = bundle.trigger_fields;
bundle.request.data = $.param({
form_id:bundle.trigger_fields.form_id
});
return bundle.request;
}
};
关于.net - 使用 .Net WebHooks 作为 RESThooks 连接到 Zapier,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35206268/
是否允许通过 POST 将文件上传到 zapier webhook? 我没能成功。在我的表单中,我有一些文本输入(姓名、电子邮件等)和一个 .这是我的 AJAX 代码: $('#__formID__
我构建了一个简单的 zapier 集成,它运行良好。但是,我正在添加动态字段。当我测试 zap 时,这一切似乎都完美无缺。我的动态表单字段和我预期的一样。 问题是将这些动态表单的值发送到我的 API。
我知道如何使用 Code by Zapier作为 zap 中的一个 Action ,但是如何将它用作 触发器?我可以很容易地设置它,但我对 zap 如何以及何时真正知道开始自己运行感到困惑?换句话说,
我们即将开始进入 Zapier 应用程序的测试流程,我有一个问题,但在 Zapier 文档中找不到答案: 问题与暂存和生产环境有关。我们设置了 2 个 Zapier 应用程序,每个环境一个。生产应用程
根据文档,如果我返回对象数组,则后续步骤将为每个对象运行。因此,如果我返回包含电子邮件地址的对象数组,并在下一步中将电子邮件发送到该地址,则电子邮件应该发送到所有地址。 var output = [
我想从我的 zapier 代码中执行 3 个不同的 api 调用,将它们的返回值放入变量中并将它们合并。我不知道该怎么做。它将像: var urls = [apiUrl1, apiUrl2, apiU
Zapier 代码文档说代码 zap 的输出可以是字典或字典列表(参见“数据变量”部分:https://zapier.com/help/code-python/)。 这样做的时候, output =
就像 this zap,我如何接受 Shopify 应用中的订单项到我的 Zapier Cli 应用中? inputFields 应该是什么?我应该如何将它们映射到 Shopify 订单项? 最佳答案
我正在使用 cli 构建一个 zapier 应用程序。 我有一个 Action ,它有一个表单,其中一个元素是一个下拉菜单,它有一个隐藏的触发器,因为它是数据源。 在 zap 的上下文中,是否可以根据
我仍然是一个初学者,并且对以下部分有疑问。目前使用 Zapier 来获取输入数据并将其拆分为 3 个不同的计算,然后将它们组合并再次将结果吐出。 第 1 位、第 2、3 位以及最后 3 位均单独处理,
致力于使用 zapier CLI 创建自定义 zapier 集成。从技术上讲,我的 API 端点不是创建,但它使用 POST 方法,因此我在 zapier 中的创建定义下创建了它。我将输出字段设置为空
我想用分支逻辑创建一个 zap。我想这样做,因为正在使用的网关/REST API 仅支持添加一个 Web Hook 。我需要一个 Zap,它可以在假设触发器返回具有“event_type”=“alph
zapier 中的 JavaScript 代码 var registerData="{'uuID':'"+uuID+"','notifTitle':'"+notifTitle+"','notifBo
我是一个完全的 JS 新手,并且正在努力提取具有多个分隔符的数据子字符串。 输入:404327 - Muskoka Cream Ale 6pack,131490 - Muskoka Cream Ale
我在 Zapier 中有一个带有 typeform 的用例,其中我收到了 2-30 个(本质上是未知数量)指向 typeform 中文件的链接,并希望使用 zapier 将它们放入数组中。 我通过通知
我是 Zapier 和编写 JavaSctipt 的新手。我尝试使用在 Zapier 中找到的 BMI 脚本来开始学习如何使用与应用程序关联的代码,但是当我在 Zapier 中测试它时,它返回此错误:
我们需要发送一个带有“OK”正文的 HTTP CODE = 200,以通过 Zapier 回复通知。 是否可以在 Zapier 中使用以下代码: var http = require('http');
我可以使用一些帮助在 Zapier 返回的数组中添加空字符串,以获取包含逗号指示的空格的电子邮件。它看起来像这样: 输入电子邮件jbrooks_ca@yahoo.com,,,,jkburtie@gma
我已经成功创建了从我的表单中读取的代码,触发表单中有多少经理和成员(公司中的任意角色)。然后它成功创建一个数组,如下所示: "managers": [ { "full_name":
背景故事:我正在尝试使用 Code By Zapier 步骤解决 Javascript 时区问题。其他触发器和操作似乎可以识别我的时区,但 Code By Zapier 步骤不会在我的计算机上运行,
我是一名优秀的程序员,十分优秀!