Как вызвать мой REST API AWS API Gateway в моем проекте iOS / Swift

Я создал приложение с одним представлением в Xcode, и затем я последовал руководству AWS Amplify iOS SDK, чтобы вставить аутентификацию с использованием моего существующего пула пользователей Cognito. Работает красиво.

Затем с помощью AWS Amplify я добавил REST API, чтобы мое приложение iOS для доступа к уже существующей таблице DynamoDB через API-шлюз, созданный Amplify, и лямбда-функцию. Однако мне пришлось все переподключить, чтобы использовать уже существующий пул пользователей Cognito, потому что Amplify CLI неожиданно создал новый пул пользователей, связанный с созданным им REST API.

Я получаю следующую ошибку при попытке вызвать свой API, и что бы я ни делал, я не могу ее устранить:

Optional("{\"message\":\"Authorization header requires \'Credential\' parameter. 
Authorization header requires \'Signature\' parameter. Authorization header requires 
\'SignedHeaders\' parameter. 
Authorization=abJarWQiOiJyR0NiTHFsbVwvbWdGeXgzcVA1YmNRaV...
403

ОБНОВЛЕНИЕ 5. Для получения дополнительных сведений см. мой Amplify выпуск SDK AWS для iOS. :)

ОБНОВЛЕНИЕ 4. Это обновление имеет приоритет над моими предыдущими обновлениями, поскольку теперь оно, похоже, устраняет указанную выше ошибку, предполагающую, что я неправильно вызываю свой REST API через аутентифицированного пользователя Cognito моего приложения iOS. Я заметил, что Amplify создал пул пользователей с двумя клиентами приложений, один для доступа в Интернет, а другой - для мобильного доступа. В моем ранее существовавшем пуле пользователей был только один клиент приложения, предназначенный для доступа в Интернет. Итак, я создал новый клиент приложения для мобильного доступа с секретом клиента приложения.

К сожалению, я получаю ту же самую ошибку. Так что мне интересно, нужно ли что-то еще перенастроить; или, возможно, у меня проблема с токеном. Как я уже упоминал в комментарии ниже, возможно, мне не следует использовать токен OIDC, как указано в руководстве по REST API? Может быть, мне следует использовать учетные данные AWS? КОНЕЦ ОБНОВЛЕНИЯ 4

В моем API есть один ресурс /items, а у меня есть ANY и OPTIONS методы. Метод ANY не имеет параметров строки запроса URL, указанных для запроса метода. Но для тела запроса RequestSchema указан тип application/json.

Моя функция вызова API - это точно та , указанная в AWS Amplify iOS SDK для REST API (я выполнил их инструкции по вызову конечной точки шлюза API с помощью авторизатора пользовательских пулов Cognito), за исключением того, что я изменил httpMethodName с POST на GET, потому что POST вызывал сбой. Вот как это выглядит:

func doInvokeAPI(token:String) {
        // change the method name, or path or the query string parameters here as desired
        let httpMethodName = "GET"
        // the guid is the partition key for the DynamoDB table
        let URLString = "/items/178dc797-4e3d-5bc4-815f-a280536fcd3a"
        //let queryStringParameters = ["key1":"{value1}"]
        let headerParameters = [
            "Content-Type": "application/json",
            "Accept": "application/json",
            "Authorization": token
        ]

        //let httpBody = "{ \n  " +
        //    "\"key1\":\"value1\", \n  " +
        //    "\"key2\":\"value2\", \n  " +
        //    "\"key3\":\"value3\"\n}"


        // Construct the request object
        let apiRequest = AWSAPIGatewayRequest(httpMethod: httpMethodName,
                                              urlString: URLString,
                                              queryParameters: nil,
                                              headerParameters: headerParameters,
                                              httpBody: nil)

...
...
        invocationClient.invoke(apiRequest).continueWith { (task: AWSTask) -> Any? in
            if let error = task.error {
                print("Error occurred: \(error)")
                // Handle error here
                return nil
            }

            // Handle successful result here
            let result = task.result!
            let responseString = String(data: result.responseData!, encoding: .utf8)

            print(responseString as Any)
            print(result.statusCode)

            return nil
        }
    }

Приведенная выше ошибка печатается этим print(responseString).

Моя таблица DynamoDB ожидает: ключ раздела userId. Управляющая строка.

Я почти уверен, что все, что я хочу передать API, - это один userId, чтобы API мог получить все связанные с ним элементы. Мой ключ сортировки не нужен.

Есть ли проблема с тем, как я выполняю этот GET-запрос через API-интерфейс API Gateway REST?

ОБНОВЛЕНИЕ 1. С моей лямбда-функцией связаны два файла JavaScript: index.js и app.js, созданные Amplify.

index.js очень короткий:

const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');

const server = awsServerlessExpress.createServer(app);

exports.handler = (event, context) => {
  console.log(`EVENT: ${JSON.stringify(event)}`);
  awsServerlessExpress.proxy(server, event, context);
};

И app.js состоит в некоторой настройке (первый снимок экрана), а затем в серии методов для get, put, post, delete. Я просто привожу два скриншота для get методов - темы этого вопроса).

введите здесь описание изображения

введите здесь описание изображения

введите здесь описание изображения

ОБНОВЛЕНИЕ 2 Вот что я вижу, когда нажимаю на запрос интеграции для ANY метода моего API. Обратите внимание, что у меня нет раскрывающегося списка для шаблона сопоставления.

введите здесь описание изображения

ОБНОВЛЕНИЕ 3 Но у меня есть Prod этап, созданный Amplify. Но я все еще нигде не вижу шаблона отображения.

введите здесь описание изображения


person motivus    schedule 10.02.2019    source источник
comment
Мне нужно увидеть вашу лямбда-функцию и схему шлюза API, снимки экрана будут работать   -  person excitedmicrobe    schedule 10.02.2019
comment
Спасибо @excitedmicrobe. Я даже не догадывался, что попал в функцию Lambda. Я только что добавил детали повторно. Лямбда-функция. Что касается схемы шлюза API ... вы имеете в виду схему или схему? Мне непонятно ...   -  person motivus    schedule 10.02.2019
comment
Извините, шаблон сопоставления API GATEWAY   -  person excitedmicrobe    schedule 10.02.2019
comment
Не стоит беспокоиться! Я только что посмотрел на Документы AWS для шаблона сопоставления. Могу ли я увидеть шаблон сопоставления через консоль AWS API Gateway для моего REST API? Самое близкое, что я нашел к чему-то похожему (но не совсем похожему) на шаблон, находится в локальном шаблоне CloudFormation для API. ?   -  person motivus    schedule 10.02.2019
comment
Шаблон сопоставления для вашего шлюза API. Шаг 1 о том, как их просмотреть: шаг 1 и шаг два: изображение шага 2 и опубликуйте то, что вы видите   -  person excitedmicrobe    schedule 10.02.2019
comment
Ах. Понятно. Я искал в нужном месте .. но я не вижу раскрывающегося списка Mapping Template. Я только что обновил свой пост скриншотом. Я очень ценю ваше понимание здесь!   -  person motivus    schedule 10.02.2019
comment
Я ценю это. Вы ОЧЕНЬ помогли ... привели меня туда, где я должен был искать. Я не знаю, почему AWS Amplify не сгенерировал шаблон сопоставления для этого REST API. Я собираюсь провести дополнительное исследование API Gateway и учту ваше предложение. Спасибо!!   -  person motivus    schedule 10.02.2019
comment
Ваш шаблон сопоставления отправляет параметры запроса вашей лямбда-функции. Без этого параметры не будут переданы, поэтому он не работает.   -  person excitedmicrobe    schedule 10.02.2019
comment
Требуется время, чтобы освоить одну страницу книги. Но я рекомендую использовать API-шлюз и Lambda для API. Использование URLSESSION на быстром. Вы можете делать все, что угодно, от аутентификации до записи динамо. Еще раз мне очень жаль, что я не могу предвидеть вашу ситуацию. Но желаю удачи   -  person excitedmicrobe    schedule 10.02.2019
comment
@excitedmicrobe .. только что вспомнил, что Amplify создал этап Prod для этого REST API. Однако я все еще не вижу шаблона сопоставления. Обновил мой пост выше.   -  person motivus    schedule 11.02.2019
comment
Вам не хватает нескольких параметров в headerParameters, которые требуются AWS для вызова запроса. Раньше я подписывал запрос вручную. docs.aws.amazon.com/general/latest/gr/   -  person Sachin Vas    schedule 11.02.2019
comment
Спасибо. Я займусь этим. Я перегрузил функцию doInvokeAPI (), как описано в документах и предположил, что у меня все хорошо в этой учетной записи, но ошибка, похоже, требует большего.   -  person motivus    schedule 11.02.2019
comment
@SachinVas, да, тип аутентификации для моего запроса метода API - AWS_IAM. Я уверен, что должно быть COGNITO_USER_POOLS. Похоже, мне нужно создать нового авторизатора для этого API. Я попробую.   -  person motivus    schedule 12.02.2019
comment
Что ж, я все еще получаю ту же ошибку, что и выше, после изменения моего типа аутентификации API на мой пул пользователей Cognito. Однако я уверен, что это был правильный шаг ... Мне просто нужно взглянуть на некоторые из этих других настроек.   -  person motivus    schedule 12.02.2019
comment
@motivus Можете ли вы отладить запрос с помощью отладчика Charles. Думаю, там можно увидеть реальный запрос и найти решение.   -  person Sachin Vas    schedule 12.02.2019
comment
У меня такое чувство, что моя проблема заключается в токене, который я передаю на шлюз API. Я думаю, мне следует использовать учетные данные AWS, а не токен OIDC. Но я не уверен. В любом случае, Чарльз (или Скрипач) определенно может помочь мне понять, что происходит за кулисами. Я установлю Чарльза!   -  person motivus    schedule 12.02.2019


Ответы (1)


"/items/{userId}" - это просто строка. Попробуйте "/items/\(userId)"

Извините, у меня недостаточно баллов, чтобы оставить комментарий.

person Don    schedule 13.02.2019
comment
userId в моем случае - это Guid, а это строка. Таким образом, приведенное выше рассматривает userId как целочисленный литерал. Тем не менее, я ценю помощь! - person motivus; 13.02.2019
comment
В Swift {userId} не будет заменяться переменной userId. Ваш URLString буквально /items/{userId}. Я почти уверен, что вы не это собирались делать. Чтобы использовать строковую интерполяцию, вам нужно использовать \(userId). Тогда ваша URLString будет /items/whateverIsInTheUserIdVariable. - person Don; 13.02.2019
comment
Я понимаю, о чем вы говорите. Это не мой код ... Я просто представляю руководство таким образом для этого поста. Другими словами, там настоящий гид. Я обновил код, чтобы он стал более понятным ... - person motivus; 13.02.2019
comment
Хорошо, спасибо за разъяснения. Вы указали, что сообщение об ошибке исходит из оператора печати, поэтому я просто предположил, что это ваш код. Надеюсь, вы решите эту проблему. Помню, как впервые работал с Cognito и API Gateway. Это был непростой опыт. - person Don; 13.02.2019
comment
Спасибо, Дон. Виноват. Вы определенно были полезны, потому что мне не следовало оставлять эту мнемонику в моем фрагменте кода. Я собираюсь проголосовать за ваш отрицательный голос, если смогу. - person motivus; 13.02.2019
comment
Потрясающие! Спасибо. - person Don; 14.02.2019