簡體   English   中英

如何將 GraphQL 查詢從 python 發送到 AppSync?

[英]How to send a GraphQL query to AppSync from python?

我們如何使用 boto 通過 AWS AppSync 發布 GraphQL 請求?

最終,我試圖模仿一個移動應用程序訪問我們在 AWS 上的無堆棧/cloudformation 堆棧,但使用 python。不是 javascript 或放大。

主要痛點是身份驗證; 我已經嘗試了十幾種不同的方法。 這是當前的一個,它生成帶有“UnauthorizedException”和“Permission denied”的“401”響應,考慮到我收到的其他一些消息,這實際上非常好。 我現在正在使用“aws_requests_auth”庫來完成簽名部分。 我假設它使用本地環境中存儲的/.aws/credentials對我進行身份驗證,或者是嗎?

對於認知身份和池將在何處以及如何進入其中,我有點困惑。 例如:說我想模仿注冊順序?

無論如何,代碼看起來很簡單; 我只是不理解身份驗證。

from aws_requests_auth.boto_utils import BotoAWSRequestsAuth

APPSYNC_API_KEY = 'inAppsyncSettings'
APPSYNC_API_ENDPOINT_URL = 'https://aaaaaaaaaaaavzbke.appsync-api.ap-southeast-2.amazonaws.com/graphql'

headers = {
    'Content-Type': "application/graphql",
    'x-api-key': APPSYNC_API_KEY,
    'cache-control': "no-cache",
}
query = """{
    GetUserSettingsByEmail(email: "john@washere"){
      items {name, identity_id, invite_code}
    }
}"""


def test_stuff():
    # Use the library to generate auth headers.
    auth = BotoAWSRequestsAuth(
        aws_host='aaaaaaaaaaaavzbke.appsync-api.ap-southeast-2.amazonaws.com',
        aws_region='ap-southeast-2',
        aws_service='appsync')

    # Create an http graphql request.
    response = requests.post(
        APPSYNC_API_ENDPOINT_URL, 
        json={'query': query}, 
        auth=auth, 
        headers=headers)

    print(response)

# this didn't work:
#    response = requests.post(APPSYNC_API_ENDPOINT_URL, data=json.dumps({'query': query}), auth=auth, headers=headers)

產量

{
  "errors" : [ {
    "errorType" : "UnauthorizedException",
    "message" : "Permission denied"
  } ]
}

這很簡單——一旦你知道。 有一些事情我沒有欣賞:

  1. 我已經假設 IAM 身份驗證
    appsync 有多種處理身份驗證的方法。 我們正在使用 IAM,所以這就是我需要處理的,您的可能會有所不同。

  2. 博托沒有進入。
    我們想像任何普通下注者一樣發出請求,他們不使用 boto,我們也不使用。 瀏覽 AWS boto 文檔是在浪費時間。

  3. 使用AWS4Auth
    我們將向 aws 發送一個常規的http 請求,因此雖然我們可以使用 python請求,但它們需要通過附加標頭進行身份驗證。 而且,當然,AWS 身份驗證標頭是特殊的,與所有其他標頭不同。 您可以嘗試自己解決如何操作,或者您可以尋找已經完成操作的其他人: Aws_requests_auth ,我開始使用的那個,可能工作得很好,但我最終使用了AWS4Auth 還有許多其他價值可疑的東西。 亞馬遜沒有認可或提供(我能找到)。

  4. appsync指定為“服務”
    我們調用什么服務? 我沒有找到任何人在任何地方這樣做的例子。 所有的例子都是微不足道的 S3 或 EC2 甚至 EB,這留下了不確定性。 我們應該與 api-gateway 服務交談嗎? 更重要的是,您將此詳細信息提供給 AWS4Auth 例程或身份驗證數據。 顯然,事后看來,該請求正在擊中 Appsync,因此它將通過 Appsync 進行身份驗證,因此在將身份驗證標頭放在一起時指定“appsync”作為服務

它匯集在一起​​為:

import requests
from requests_aws4auth import AWS4Auth

# Use AWS4Auth to sign a requests session
session = requests.Session()
session.auth = AWS4Auth(
    # An AWS 'ACCESS KEY' associated with an IAM user.
    'AKxxxxxxxxxxxxxxx2A',
    # The 'secret' that goes with the above access key.                    
    'kwWxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxgEm',    
    # The region you want to access.
    'ap-southeast-2',
    # The service you want to access.
    'appsync'
)
# As found in AWS Appsync under Settings for your endpoint.
APPSYNC_API_ENDPOINT_URL = 'https://nqxxxxxxxxxxxxxxxxxxxke'
                           '.appsync-api.ap-southeast-2.amazonaws.com/graphql'
# Use JSON format string for the query. It does not need reformatting.
query = """
    query foo {
        GetUserSettings (
           identity_id: "ap-southeast-2:8xxxxxxb-7xx4-4xx4-8xx0-exxxxxxx2"
        ){ 
           user_name, email, whatever 
}}"""
# Now we can simply post the request...
response = session.request(
    url=APPSYNC_API_ENDPOINT_URL,
    method='POST',
    json={'query': query}
)
print(response.text)

哪個產量

# Your answer comes as a JSON formatted string in the text attribute, under data. 
{"data":{"GetUserSettings":{"user_name":"0xxxxxxx3-9102-42f0-9874-1xxxxx7dxxx5"}}}

獲取憑據

要擺脫硬編碼的密鑰/秘密,您可以使用本地 AWS ~/.aws/config~/.aws/credentials ,它是通過這種方式完成的......

# Use AWS4Auth to sign a requests session
session = requests.Session()
credentials = boto3.session.Session().get_credentials()
session.auth = AWS4Auth(
    credentials.access_key,
    credentials.secret_key,
    boto3.session.Session().region_name,
    'appsync',
    session_token=credentials.token
)
...<as above>

這似乎確實尊重環境變量AWS_PROFILE以承擔不同的角色。

請注意, STS.get_session_token不是這樣做的方法,因為它可能會嘗試從角色中承擔角色,具體取決於它的關鍵字與 AWS_PROFILE 值匹配的位置。 credentials文件中的標簽將起作用,因為密鑰就在那里,但在config文件中找到的名稱不起作用,因為它已經假定了一個角色。

您可以在 AppSync 端設置 API 密鑰並使用下面的代碼。 這適用於我的情況。

import requests
from requests_aws4auth import AWS4Auth
import boto3

# establish a session with requests session
session = requests.Session()

# As found in AWS Appsync under Settings for your endpoint.
APPSYNC_API_ENDPOINT_URL = 'https://vxxxxxxxxxxxxxxxxxxy.appsync-api.ap-southeast-2.amazonaws.com/graphql'

# setup the query string (optional)
query = """query listItemsQuery {listItemsQuery {items {correlation_id, id, etc}}}"""

# Now we can simply post the request...
response = session.request(
    url=APPSYNC_API_ENDPOINT_URL,
    method='POST',
    headers={'x-api-key': '<APIKEYFOUNDINAPPSYNCSETTINGS>'},
    json={'query': query}
)

print(response.json()['data'])

根據 Joseph Warda 的回答,您可以使用下面的類來發送 AppSync 命令。

# fileName: AppSyncLibrary

import requests

class AppSync():
    def __init__(self,data):
        endpoint = data["endpoint"]
        self.APPSYNC_API_ENDPOINT_URL = endpoint
        self.api_key = data["api_key"]
        self.session = requests.Session()

    def graphql_operation(self,query,input_params):

        response = self.session.request(
            url=self.APPSYNC_API_ENDPOINT_URL,
            method='POST',
            headers={'x-api-key': self.api_key},
            json={'query': query,'variables':{"input":input_params}}
        )

        return response.json()

例如在同一目錄中的另一個文件中:

import AppSync from AppSyncLibrary

APPSYNC_API_ENDPOINT_URL = {YOUR_APPSYNC_API_ENDPOINT}
APPSYNC_API_KEY = {YOUR_API_KEY}

init_params = {"endpoint":APPSYNC_API_ENDPOINT_URL,"api_key":APPSYNC_API_KEY)

app_sync = AppSync(init_params)

mutation = """mutation CreatePost($input: CreatePostInput!) {
createPost(input: $input) {
  id
  content
 }
}
"""

input_params = {
  "content":"My first post"
}

response = app_sync.graphql_operation(mutation,input_params)

print(response)

注意:這需要您為 AppSync API 激活 API 訪問權限。 查看此AWS 帖子以了解更多詳細信息。

由於代表較低,我無法添加評論,但我只想補充一點,我嘗試了接受的答案,但沒有奏效。 我收到一條錯誤消息,說我的 session_token 無效。 可能是因為我使用的是 AWS Lambda。

我讓它幾乎完全正常工作,但是通過添加到 aws4auth 對象的會話令牌參數。 這是完整的部分:

import requests
import os
from requests_aws4auth import AWS4Auth

def AppsyncHandler(event, context):

    # These are env vars that are always present in an AWS Lambda function
    # If not using AWS Lambda, you'll need to add them manually to your env.

    access_id = os.environ.get("AWS_ACCESS_KEY_ID")
    secret_key = os.environ.get("AWS_SECRET_ACCESS_KEY")
    session_token = os.environ.get("AWS_SESSION_TOKEN")
    region = os.environ.get("AWS_REGION")

    # Your AppSync Endpoint
    api_endpoint = os.environ.get("AppsyncConnectionString")
    
    resource = "appsync"
    

    session = requests.Session()
    session.auth = AWS4Auth(access_id, 
                            secret_key, 
                            region, 
                            resource, 
                            session_token=session_token)

其余的都是一樣的。

graphql-python/gql版本 3.0.0rc0 開始支持 AWS AppSync。

它支持實時端點上的查詢、變異甚至訂閱。

該文檔可在此處獲得

以下是使用 API 密鑰身份驗證的更改示例:

import asyncio
import os
import sys
from urllib.parse import urlparse

from gql import Client, gql
from gql.transport.aiohttp import AIOHTTPTransport
from gql.transport.appsync_auth import AppSyncApiKeyAuthentication

# Uncomment the following lines to enable debug output
# import logging
# logging.basicConfig(level=logging.DEBUG)


async def main():

    # Should look like:
    # https://XXXXXXXXXXXXXXXXXXXXXXXXXX.appsync-api.REGION.amazonaws.com/graphql
    url = os.environ.get("AWS_GRAPHQL_API_ENDPOINT")
    api_key = os.environ.get("AWS_GRAPHQL_API_KEY")

    if url is None or api_key is None:
        print("Missing environment variables")
        sys.exit()

    # Extract host from url
    host = str(urlparse(url).netloc)

    auth = AppSyncApiKeyAuthentication(host=host, api_key=api_key)

    transport = AIOHTTPTransport(url=url, auth=auth)

    async with Client(
        transport=transport, fetch_schema_from_transport=False,
    ) as session:

        query = gql(
            """
mutation createMessage($message: String!) {
  createMessage(input: {message: $message}) {
    id
    message
    createdAt
  }
}"""
        )

        variable_values = {"message": "Hello world!"}

        result = await session.execute(query, variable_values=variable_values)
        print(result)


asyncio.run(main())

希望這對大家有幫助

import requests
import json
import os
from dotenv import load_dotenv
load_dotenv(".env")


class AppSync(object):
    def __init__(self,data):
        endpoint = data["endpoint"]
        self.APPSYNC_API_ENDPOINT_URL = endpoint
        self.api_key = data["api_key"]
        self.session = requests.Session()

    def graphql_operation(self,query,input_params):

        response = self.session.request(
            url=self.APPSYNC_API_ENDPOINT_URL,
            method='POST',
            headers={'x-api-key': self.api_key},
            json={'query': query,'variables':{"input":input_params}}
        )

        return response.json()



def main():
    APPSYNC_API_ENDPOINT_URL = os.getenv("APPSYNC_API_ENDPOINT_URL")
    APPSYNC_API_KEY = os.getenv("APPSYNC_API_KEY")
    init_params = {"endpoint":APPSYNC_API_ENDPOINT_URL,"api_key":APPSYNC_API_KEY}
    app_sync = AppSync(init_params)

    mutation = """
   query MyQuery {
          getAccountId(id: "5ca4bbc7a2dd94ee58162393") {
            _id
            account_id
            limit
            products
          }
        }
    """

    input_params = {}

    response = app_sync.graphql_operation(mutation,input_params)
    print(json.dumps(response , indent=3))

main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM