2017-03-16 111 views
2

我是一名Python初学者,尝试构建一种服务,它从api.ai获取信息,将其传递给API,然后从其返回的JSON中返回一条确认消息。Python Webhook:传递URL +有效载荷

app.py:

#!/usr/bin/env python 

from __future__ import print_function 
from future.standard_library import install_aliases 
install_aliases() 

from urllib.parse import urlparse, urlencode 
from urllib.request import urlopen, Request 
from urllib.error import HTTPError 

import json 
import os 
import sys 
import logging 

from flask import Flask, render_template 
from flask import request 
from flask import make_response 

# Flask app should start in global layout 
app = Flask(__name__) 
app.logger.addHandler(logging.StreamHandler(sys.stdout)) 
app.logger.setLevel(logging.ERROR) 

@app.route('/webhook', methods=['POST']) 

def webhook(): 
    req = request.get_json(silent=True, force=True) 

    print("Request:") 
    print(json.dumps(req, indent=4)) 

    res = processRequest(req) 

    res = json.dumps(res, indent=4) 
    # print(res) 
    r = make_response(res) 
    r.headers['Content-Type'] = 'application/json' 
    return r 

def processRequest(req): 
    if req.get("result").get("action") != "bookMyConference": 
     return {} 

    #oauth 
    orequest = req.get("originalRequest") # work down the tree 
    odata = orequest.get("data") # work down the tree 
    user = odata.get("user") # work down the tree 
    access_token = user.get("access_token") 

    #data 
    result = req.get("result") # work down the tree 
    parameters = result.get("parameters") # work down the tree 
    startdate = parameters.get("start-date") 
    meetingname = parameters.get("meeting-name") 

    payload = { 
     "start-date": startdate, 
     "end-date": startdate, 
     "meeting-name": meetingname 
    } 

    # POST info to join.me 
    baseurl = "https://api.join.me/v1/meetings" 
    p = Request(baseurl) 
    p.add_header('Content-Type', 'application/json; charset=utf-8') 
    p.add_header('Authorization', 'Bearer ' + access_token) #from oauth 
    jsondata = json.dumps(payload) 
    jsondataasbytes = jsondata.encode('utf-8') # needs to be bytes 
    jresult = urlopen(p, jsondataasbytes).read() 
    data = json.loads(jresult) 
    res = makeWebhookResult(data) 
    return res 

def makeWebhookResult(data): 

    speech = "Appointment scheduled!" 

    print("Response:") 
    print(speech) 

    return { 
     "speech": speech, 
     "displayText": speech, 
     # "data": data, 
     "source": "heroku-bookmyconference" 
    } 


if __name__ == '__main__': 
    port = int(os.getenv('PORT', 5000)) 

    print("Starting app on port %d" % port) 

    app.run(debug=False, port=port, host='0.0.0.0') 

编辑4:这是我得到我的Heroku的日志中的错误:

2017-03-21T19:06:09.383612+00:00 app[web.1]: HTTPError: HTTP Error 400: Bad Request

回答

0

借用here,使用urlib模块内processRequest()你可以像这样将你的有效载荷添加到urlopen:

req = Request(yql_url) 
req.add_header('Content-Type', 'application/json; charset=utf-8') 
jsondata = json.dumps(payload) 
jsondataasbytes = jsondata.encode('utf-8') # needs to be bytes 
result = urlopen(req, jsondataasbytes).read() 
data = json.loads(result) 

事情变得更简洁,如果使用requests模块:

headers = {'content-type': 'application/json'} 
result = requests.post(yql_url, data=json.dumps(payload), headers=headers) 
data = result.json() 

编辑:添加一些细节具体到join.me API

纵观join.me docs你需要获得访问令牌添加到您的标题。但是在获得访问令牌之前,您还需要一个应用验证码。您可以手动获取应用认证代码,或链接一些重定向。

要开始,请在浏览器中尝试此网址,并从回调参数中获取code。使用您的join.me creds:

auth_url = 'https://secure.join.me/api/public/v1/auth/oauth2' \ 
    + '?client_id=' + client_id \ 
    + '&scope=scheduler%20start_meeting' \ 
    + '&redirect_uri=' + callback_url \ 
    + '&state=ABCD' \ 
    + '&response_type=code' 
print(auth_url) # try in browser 

为了获得访问令牌:

token_url = 'https://secure.join.me/api/public/v1/auth/token' 
headers = {'content-type': 'application/json'} 
token_params = { 
    'client_id': client_id, 
    'client_secret': client_secret, 
    'code': auth_code, 
    'redirect_uri': callback_url, 
    'grant_type': 'authorization_code' 
} 
result = requests.post(token_url, data=json.dumps(token_params), headers=headers) 
access_token = result.json().get('access_token') 

然后你的帖子/会议头将需要看起来像:

headers = { 
    'content-type': 'application/json', 
    'Authorization': 'Bearer ' + access_token 
} 
+0

我我已经添加到我的processRequest()调用,但我现在得到这个错误,当我试图打它“状态”:{ “code”:206, “errorType”:“partial_content”, “ errorDet ails“:”Webhook通话失败。错误消息:Webhook响应为空.' – beaconhill

+0

数据在返回时看起来像什么?这听起来像它可能需要一些[格式](https://discuss.api.ai/t/webhook-error-206/976/7)。 – brennan

+0

只是对显示更多的原始帖子进行了编辑。我得到一个401,因为我没有通过访问令牌。如何从请求中访问它? – beaconhill