Метод API Gateway POST работает во время тестов, но не с почтальоном - PullRequest
0 голосов
/ 26 марта 2019

Я постараюсь объяснить мою проблему ясно.

У меня есть API, который пишет что-то в DynamoDB с помощью лямбда-функции, написанной в Node.js. Когда я вызываю его в консоли AWS, API работает как положено. Я отправляю такое тело:

{
        "user-id":"4dz545zd",
        "name":"Bush",
        "firstname":"Gerard",
}

И это создает запись в моей таблице DynamoDB. Но когда я вызываю тот же API (недавно развернутый) с Почтальоном, я получаю эту ошибку:

{
    "statusCode": "400",
    "body": "One or more parameter values were invalid: An AttributeValue may not contain an empty string",
    "headers": {
        "Content-Type": "application/json"
    }
}

Когда я проверяю в cloudwatch, почему он не работает, я вижу: Тело запроса метода перед преобразованиями: [Binary Data]

Это странно, потому что я отправил JSON с двумя заголовками:

Content-Type:application/json
Accept:application/json

А затем в cloudwatch я вижу, что обрабатывается:

{
        "user-id":"",
        "name":"",
        "firstname":"",
}

Это объясняет ошибку, но я не понимаю, почему, когда я отправляю его почтальоном, не будучи пустым, в формате json, он все равно отправляет его как «двоичные» данные, и поэтому не обрабатывается моим правило отображения (и поэтому лямбда обрабатывает его с пустым json):

#set($inputRoot = $input.path('$'))
  {
  "httpMethod": "POST",
  "body": {
    "TableName": "user",
    "Item": { 
        "user-id":"$inputRoot.get('user-id')",
        "name":"$inputRoot.get('name')",
        "firstname":"$inputRoot.get('firstname')",
                }
            }
}

Заранее спасибо!

РЕДАКТИРОВАТЬ: я добавляю функцию лямбда-кода

'use strict';

console.log('Function Prep');
const doc = require('dynamodb-doc');
const dynamo = new doc.DynamoDB();

exports.handler = (event, context, callback) => {

    const done = (err, res) => callback(null, {
        statusCode: err ? '400' : '200',
        body: err ? err.message : res,
        headers: {
            'Content-Type': 'application/json'
        },
    });

    switch (event.httpMethod) {
        case 'DELETE':
            dynamo.deleteItem(event.body, done);
            break;
        case 'HEAD':
            dynamo.getItem(event.body, done);
            break;
        case 'GET':
            if (event.queryStringParameters !== undefined) {
                dynamo.scan({ TableName: event.queryStringParameters.TableName }, done);
            }
            else {
                dynamo.getItem(event.body, done);
            }
            break;
        case 'POST':
            dynamo.putItem(event.body, done);
            break;
        case 'PUT':
            dynamo.putItem(event.body, done);
            break;
        default:
            done(new Error(`Unsupported method "${event.httpMethod}"`));
    }
};

1 Ответ

1 голос
/ 26 марта 2019

Это потому, что при тестировании с консоли AWS Lambda вы отправляете JSON, который вы на самом деле ожидаете. Но когда это вызывается из API Gateway, событие выглядит иначе.

Вам понадобится получить доступ к объекту event.body, чтобы получить JSON, однако тело представляет собой Stringified JSON, то есть вам придется сначала его проанализировать.

Вы не указали, на каком языке вы кодируете, но если вы используете NodeJS, вы можете разобрать тело следующим образом:

JSON.parse(event.body).

Если вы используете Python, вы можете сделать это:

json.loads(event["body"])

Если вы используете любой другой язык, я предлагаю вам посмотреть, как анализировать JSON из заданной строки

Это дает то, что вам нужно.

Вот как выглядит событие из API Gateway:

{
    "path": "/test/hello",
    "headers": {
      "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
      "Accept-Encoding": "gzip, deflate, lzma, sdch, br",
      "Accept-Language": "en-US,en;q=0.8",
      "CloudFront-Forwarded-Proto": "https",
      "CloudFront-Is-Desktop-Viewer": "true",
      "CloudFront-Is-Mobile-Viewer": "false",
      "CloudFront-Is-SmartTV-Viewer": "false",
      "CloudFront-Is-Tablet-Viewer": "false",
      "CloudFront-Viewer-Country": "US",
      "Host": "wt6mne2s9k.execute-api.us-west-2.amazonaws.com",
      "Upgrade-Insecure-Requests": "1",
      "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
      "Via": "1.1 fb7cca60f0ecd82ce07790c9c5eef16c.cloudfront.net (CloudFront)",
      "X-Amz-Cf-Id": "nBsWBOrSHMgnaROZJK1wGCZ9PcRcSpq_oSXZNQwQ10OTZL4cimZo3g==",
      "X-Forwarded-For": "192.168.100.1, 192.168.1.1",
      "X-Forwarded-Port": "443",
      "X-Forwarded-Proto": "https"
    },
    "pathParameters": {
      "proxy": "hello"
    },
    "requestContext": {
      "accountId": "123456789012",
      "resourceId": "us4z18",
      "stage": "test",
      "requestId": "41b45ea3-70b5-11e6-b7bd-69b5aaebc7d9",
      "identity": {
        "cognitoIdentityPoolId": "",
        "accountId": "",
        "cognitoIdentityId": "",
        "caller": "",
        "apiKey": "",
        "sourceIp": "192.168.100.1",
        "cognitoAuthenticationType": "",
        "cognitoAuthenticationProvider": "",
        "userArn": "",
        "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36 OPR/39.0.2256.48",
        "user": ""
      },
      "resourcePath": "/{proxy+}",
      "httpMethod": "GET",
      "apiId": "wt6mne2s9k"
    },
    "resource": "/{proxy+}",
    "httpMethod": "GET",
    "queryStringParameters": {
      "name": "me"
    },
    "stageVariables": {
      "stageVarName": "stageVarValue"
    },
    "body": "'{\"user-id\":\"123\",\"name\":\"name\", \"firstname\":\"firstname\"}'"
  }

EDIT

После дальнейшего обсуждения в комментариях еще одна проблема заключается в том, что вы используете API-интерфейс DynamoDB, а не API-интерфейс DocumentClient. При использовании API DynamoDB вы должны указать типы ваших объектов. С другой стороны, DocumentClient устраняет эту сложность.

Я также немного реорганизовал ваш код (в настоящее время только для простоты), поэтому вы можете использовать async / await

'use strict';

console.log('Function Prep');
const AWS = require('aws-sdk');
const dynamo = new AWS.DynamoDB.DocumentClient();

exports.handler = async (event) => {

    switch (event.httpMethod) {
        case 'POST':
            await dynamo.put({TableName: 'users', Item: JSON.parse(event.body)}).promise();
            break;
        default:
            throw new Error(`Unsupported method "${event.httpMethod}"`);
    }
    return {
        statusCode: 200,
        body: JSON.stringify({message: 'Success'})
    }
};

Вот элемент в DynamoDB:

enter image description here

А это мой запрос почтальона:

enter image description here

С правильными заголовками:

enter image description here

При создании API Gateway я установил флажок Use Lambda Proxy integration. Мой API выглядит так:

enter image description here

Если вы воспроизводите эти шаги, это должно сработать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...