質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.53%

  • AWS(Amazon Web Services)

    2472questions

    Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

  • Node.js

    2289questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • API

    1788questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • JSON

    1415questions

    JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

  • Slack

    226questions

    Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。

AWS LambdaのNode.jsとJSONについて

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,012

HiroakiKamei

score 2

はじめまして、Node.js初心者です。
前回に続き、GoogleHomeからSlackに投稿したいです。

 前提・実現したいこと

GoogleHome→Dialogflow→APIGateway→AWSLambda→Slack

参考にしたサイト様
Dialogflow入門
AWS API Gateway+LambdaでSlackにメッセージをPOSTする(前編)
Google Home と Lambda で「"あ"のつくポケモンなーんだ」

DialogflowのFulfillmentでAPIGatewayをあてており、
Lambdaでこのコードを入れたところエラーがでます。
Dialogflow側では問題なくJSONが送られている状態です。

 発生している問題・エラーメッセージ

{
  "errorMessage": "RequestId: f396756f-0a52-11e8-967f-79dda54dff68 Process exited before completing request"
}

 該当のソースコード

console.log('Loading function');

const https = require('https');
const url = require('url');
const slack_url = process.env.SLACK_WEBHOOK_URL;
const slack_req_opts = url.parse(slack_url);
slack_req_opts.method = 'POST';
slack_req_opts.headers = {'Content-Type': 'application/json'};

exports.handler = function(event, context, callback) {
  if (!event.text) {
    callback('called without event.text');
    return;
  }
  var req = https.request(slack_req_opts, function (res) {
    if (res.statusCode === 200) {
      callback(null, 'posted to slack');
    } else {
      callback('status code: ' + res.statusCode);
    }
    });

    req.on('error', function(e) {
      console.log('problem with request: ' + e.message);
      context.fail(e.message);
    });

    // メッセージの編集
    const parameters = JSON.parse(event.body).result.parameters;
    var message = parameters.date + parameters.building + parameters.request;
    var slack_text = message;

    req.write(JSON.stringify({text: slack_text}));

    req.end();
};

 試したこと

上記の部分を下記に変更すれば問題なく動くのですが、ただ単にLambdaのテストで設定したテキストがSlackに送られる状況です。

 // メッセージの編集
    const parameters = JSON.parse(event.body).result.parameters;
    var message = parameters.date + parameters.building + parameters.request;
    var slack_text = message;
 // メッセージの編集
    var message = (event.text);
    var slack_text = message;

 補足情報

エラーコードをググって見たところ、処理が途中で終了してしまうと発生してしまうようで、
CloudWatchからエラーを探ったところ、

SyntaxError: Unexpected token u in JSON at position 0
at Object.parse (native)
at exports.handler (/var/task/index.js:29:29)


とでています。調べると
Uncaught Syntaxerror: Unexpected token u

コールバックと引数が一致していない?のでしょうか
ここからハマってしまいわからない状況です。

ご回答ご教授願います、よろしくお願いします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

SyntaxError: Unexpected token u in JSON at position 0
コールバックと引数が一致していない?のでしょうか

いいえ。JSON.parseしようとしたevent.bodyがundefinedだった可能性が高いです。例えば以下のコードで同様のエラーが得られます。

const data = {};
JSON.parse(data.foo);

JSON.parseは渡されたJSONの文字列の先頭が{なら「Objectかな…」[なら「Arrayかな…」、1なら「Numberかな…」、と解析できますが、undefinedだと「先頭uなの!?」となって、結局

SyntaxError: Unexpected token u in JSON at position 0

とエラーを出して止まります。

エラーを先まで見ると、どこで止まったかが書いてあります。
イメージ説明
スクリプトの29行目の29文字目でエラーになったようです。スクリプトの29行目を確認しましょう。

    // メッセージの編集
    const parameters = JSON.parse(event.body).result.parameters;


JSON.parseのところだと分かります。このことから、event.bodyが変で、JSONの文字列が渡らなかったのかな、と予想できます。なので、原因を調べるために、以下のように1行追加して、もう一度テストしてみてください。困ったときは、おかしい行の前でconsole.logすれば、たいていの問題は原因がわかります。

    // メッセージの編集
    console.log(event); // 追加
    const parameters = JSON.parse(event.body).result.parameters;

今回の場合、API Gatewayからのアクセス、つまり、HTTPのリクエストがトリガーとなります。このときのeventオブジェクトには、HTTPのヘッダの情報やアクセス元の情報が入っていて、Lambdaのコンソールからテストしたときのような、単純な構造にはなっていません。

Lambdaのコンソールには、API Gatewayからのeventオブジェクトっぽいものでテストするサンプルがありますので、それを使いましょう。

テストイベントの設定から、
イメージ説明

API Gateway AWS Proxyを選び、
イメージ説明

2行目のbodyにJSONを書いてテストしてください。
イメージ説明

ここが問題なければ、AWSLambda → Slackは問題ありません。
次はAPIGatewayのコンソールからAPIGateway → AWSLambdaをテストしましょう。

イメージ説明

リクエスト本文にJSONを書いてテストしてください。

ここが問題なければ、APIGateway → AWSLambdaも問題ありません。
次はDialogflow → APIGatewayを確認することになりますが、長くなったので回答はここまでとします。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/02/07 10:14 編集

    こんにちは、前回に引き続き丁寧な解説とご迅速な回答ありがとうございます....!!
    こちらの返答が遅れてしまいすみません。

    ご指摘があったようにLambdaのテストのところにAPIgatewayをあて、
    bodyに内容をいれたところエラーがでました。

    SyntaxError: Unexpected token o in JSON at position 1
    at Object.parse (native)
    at exports.handler (/var/task/index.js:30:29)

    u→o でオブジェクトになっているとのエラーだと思うのですが、
    テストコードのJSONの書き方がわるいのでしょうか?

    {
    "text": "Posted Slack",
    "body": {
    "result": {
    "parameters": {
    "request": "出社",
    "date": "2018-02-06",
    "building": "本社",
    "place": "東京",
    "time": "08:30:00"
    }
    }
    },
    "resource": "/{proxy+}",
    "requestContext": {
    "resourceId": "123456",
    "apiId": "1234567890",
    "resourcePath": "/{proxy+}",
    //以下略

    よろしくお願いします。

    キャンセル

  • 2018/02/07 10:47

    3枚目の画像の2行目のところを見てください。bodyはHTTPのリクエストのbodyで、文字列で指定します。したがって、{foo: 'bar'}を送るには、"{\"foo\": \"bar\"}"のようにJSONをJSONの中に書かないといけません。面倒な場合は、ブラウザのコンソールなどでJSON.stringify(JSON.stringify({foo: 'bar'}))とするといいです。

    キャンセル

  • 2018/02/07 18:03

    回答ありがとうございます、無事AWSLambda → Slackへ送れました!!
    引き続きAPIGatewayでテストしてみようと思います、ありがとうございます。

    キャンセル

  • 2018/02/07 19:03

    度々すいません、APIGatewayで実際にDialogflowから流れてくるJSONを入れたところエラーが出てしまいます...

    "errorMessage": "RequestId: bcfe69c8-0beb-11e8-8ad0-dfc413bf363b Process exited before completing request"
    }
    レスポンスヘッダー
    {"X-Amzn-Trace-Id":"sampled=0;root=1-5a7acae7-40080432fcbeae52d359a94b","Content-Type":"application/json"]

    キャンセル

  • 2018/02/07 20:06

    Lambdaはうまくいったようでよかったです。API Gatewayのエラーについては
    (1) まず、Lambdaのログにもエラーがででいるはずですので、確認してみてください。
    (2) API Gatewayでテストするときのリクエスト本文を確認してみてください。ここは、JSONのJSONではなく、JSONで大丈夫です。{"body": "hello"} のような感じです。原因はおそらくここじゃないかと思っています。

    キャンセル

  • 2018/02/08 11:34 編集

    おはようございます、ご返信ありがとうございます。

    (1)Lambda側では
    SyntaxError: Unexpected token o in JSON at position 1
    とでています。APIGatewayでは(2)で仰られたように

    {
    "text": "Posted Slack",
    "body": {
    "result": {
    "parameters": {
    "request": "出社",
    "date": "2018-02-06",
    "building": "本社",
    "place": "東京",
    "time": "08:30:00"
    }
    }
    }

    を入れて実行しています...

    キャンセル

  • 2018/02/08 15:20

    console.log(event)
    は書いてありますか?
    Lambdaでエラーが検知できたということは、console.logで原因がわかるはずですので、console.log(event)して、event.bodyとしてどんなものが渡ってきたのかを確認してください。

    console.log(event)
    は完成するまで残しておいて、何かあったらすぐに確認できようにしておくといいです。

    別件ですが、そのテストデータだと、
    JSON.parse(event.body).result.parameters
    が取れません。
    {"text": ..., "body": {"result": ...}}
    ではなくて、
    {"result": ...}
    が正しいのではないでしょうか。逆に、そのテストデータが正しいなら、Lambdaの方を修正する必要がありますね。

    キャンセル

  • 2018/02/13 12:31

    おはようございます、コメントありがとうございます。
    返信が遅れてしまいましてすいません。

    console.log(event)で渡ってきたものは

    { result:
    { parameters:
    { request: '出社',
    date: '2018-02-06',
    building: '本社',
    place: '東京',
    time: '08:30:00' } } }

    で、(ご指摘があったのでテストデータを{"result": ...}に変更しました)

    その後に続くエラーが

    SyntaxError: Unexpected token u in JSON at position 0
    at Object.parse (native)
    at exports.handler (/var/task/index.js:30:29)

    となっています。

    キャンセル

同じタグがついた質問を見る

  • AWS(Amazon Web Services)

    2472questions

    Amazon Web Services (AWS)は、仮想空間を機軸とした、クラスター状のコンピュータ・ネットワーク・データベース・ストーレッジ・サポートツールをAWSというインフラから提供する商用サービスです。

  • Node.js

    2289questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • API

    1788questions

    APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

  • JSON

    1415questions

    JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

  • Slack

    226questions

    Slackは、Tiny Speckという企業からリリースされたコミュニケーションツールです。GoogleDriveやGitHubなど、さまざまな外部サービスと連携することができます。