UnknownOperationException: GraphQl Appsync with AWS API Gateway - proxy

I have integrated API Gateway as a proxy to AWS AppSync data plane via AWS CDK. I am trying to test the connection between API Gateway and AWS Appsync. I am getting to UnknownOperationException while testing calling appsync endpoint via the API gateway.
Below are the code snippet
const api = new appsync.GraphqlApi(this, 'UserApi', {
name: 'user-appsync-api',
schema: appsync.Schema.fromAsset('lib/graphql/schema.graphql'),
authorizationConfig: {
defaultAuthorization: {
authorizationType: appsync.AuthorizationType.API_KEY,
apiKeyConfig: {
expires: cdk.Expiration.after(cdk.Duration.days(365))
}
},
},
xrayEnabled: true,
});
const createUserAPIGraphQl = apigateway.root.addResource('user-graphql');
createUserAPIGraphQl.addMethod("POST", new apigw.AwsIntegration({
service: 'appsync-api',
region: 'us-east-1',
subdomain: 'adsdasdsadasdasd',
integrationHttpMethod: 'POST',
path: 'user-graphql',
options: {
passthroughBehavior: PassthroughBehavior.WHEN_NO_TEMPLATES,
credentialsRole: ApiGatewayAppSyncRole,
integrationResponses: [{
statusCode: '200'
}]
},
}
), {
methodResponses: [
{
statusCode: '200',
responseModels: {
'application/json': Model.EMPTY_MODEL
}
},
]
});
RequestBody
{
"query": "query getNoteById { getNoteById(noteId: \"001\") { id }}"
}
Error:
{
"errors": [
{
"errorType": "UnknownOperationException",
"message": "Unknown Operation Request."
}
]
}
API Gateway Logs:
Mon Jul 11 10:20:21 UTC 2022 : Endpoint response body before transformations:
{
"errors" : [ {
"errorType" : "UnknownOperationException",
"message" : "Unknown Operation Request."
} ]
}

Related

User is not authorized to perform: dynamodb:CreateTable on resource:

When I tried to run my lambda function register which queries the table example_user, it will throw the error below. My code is only trying to get data from the table example_user and not create any table.
{"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"AccessDeniedException: User: arn:aws:sts::577777777777:assumed-role/example-user-api-dev-ap-southeast-1-lambdaRole/example-user-api-dev-register is not authorized to perform: dynamodb:CreateTable on resource: arn:aws:dynamodb:ap-southeast-1:577777777777:table/example_user","reason":{"errorType":"AccessDeniedException","errorMessage":"User: arn:aws:sts::577777777777:assumed-role/example-user-api-dev-ap-southeast-1-lambdaRole/example-user-api-dev-register is not authorized to perform: dynamodb:CreateTable on resource: arn:aws:dynamodb:ap-southeast-1:577777777777:table/example_user"
The error was thrown after 13 UserController with email
This is my codes:
User.js
const schema = new dynamoose.Schema({
"email": String,
"uid": String,
"name": String,
"gender": {
"type": Number,
"default": 0
},
"profileImageType": {
"type": Number,
"default": 0
},
"profileImage": String,
"accountType": Number,
}, {
"saveUnknown": true,
"timestamps": true
});
module.exports = dynamoose.model('example_user', schema);
UserController.js
const User = require("./User.js");
exports.getProfile = async function(email,res){
console.log("13 UserController with email " + email)
var profile = await User.get(email)
console.log("15 profile")
console.log(profile)
if (profile){
return profile;
}else{
return false;
}
};
Below is a snippet from my serverless.yml file
iamRoleStatements:
- Effect: "Allow"
Action:
- "s3:*"
Resource:
- "arn:aws:s3:::profiles.example.app/*"
- Effect: "Allow"
Action:
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
Resource:
- "arn:aws:dynamodb:ap-southeast-1:577777777777:table/example_user"
You should be able to do dynamoose.model('example_user', schema, {"create": false}) to get away from the need to create a table https://dynamoosejs.com/guide/Model/

AWS - Configuring Lambda Destinations with SNS

I'm trying to configure an AWS Lambda function to pipe its output into an SNS notification, but it doesn't seem to work. The function executes successfully in the Lambda console and I can see the output is correct, but SNS never seems to be getting notified or publishing anything. I'm working with Terraform to stand up my infra, here is the Terraform code I'm using, maybe someone can help me out:
resource "aws_lambda_function" "lambda_apigateway_to_sns_function" {
filename = "../node/lambda.zip"
function_name = "LambdaPublishToSns"
handler = "index.snsHandler"
role = aws_iam_role.lambda_apigateway_to_sns_execution_role.arn
runtime = "nodejs12.x"
}
resource "aws_iam_role" "lambda_apigateway_to_sns_execution_role" {
assume_role_policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Effect": "Allow"
}
]
}
POLICY
}
resource "aws_iam_role_policy_attachment" "apigateway_to_sns_sns_full_access" {
policy_arn = "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
role = aws_iam_role.lambda_apigateway_to_sns_execution_role.name
}
resource "aws_lambda_function_event_invoke_config" "example" {
function_name = aws_lambda_function.lambda_apigateway_to_sns_function.arn
destination_config {
on_success {
destination = aws_sns_topic.sns_topic.arn
}
on_failure {
destination = aws_sns_topic.sns_topic.arn
}
}
}
And here's my Lambda function code (in NodeJS):
exports.snsHandler = (event, context, callback) => {
context.callbackWaitsForEmptyEventLoop = false;
callback(null, {
statusCode: 200,
body: event.body + " apigateway"
);
}
(the function is supposed to take input from API Gateway, and whatever is in the body of the API Gateway request, just append "apigateway" to the end of it and pass the message on; I've tested the integration with API Gateway and that integration works perfectly)
Thanks!

Apollo Server running as a gateway is hiding remote error if data is not null

I'm running an apollo-server-express as a gateway application. Setting up a few underlying GraphQL Applications with makeRemoteExecutableSchema and an apollo-link-http.
Usually every call just works. If an error is part of the response and data is null it also works. But if data contains just the data and errors contains an error. Data will be passed though but errors is empty
const headerSet = setContext((request, previousContext) => {
return setHeaders(previousContext);
});
const errorLink = onError(({ response, forward, operation, graphQLErrors, networkError }) => {
if (graphQLErrors) {
graphQLErrors.map((err) => {
Object.setPrototypeOf(err, Error.prototype);
});
}
if (networkError) {
logger.error(networkError, 'A wild network error appeared');
}
});
const httpLink = new HttpLink({
uri: remoteURL,
fetch
});
const link = headerSet.concat(errorLink).concat(httpLink);
Example A "Working Example":
Query
{
checkName(name: "namethatistoolooooooong")
}
Query Response
{
"errors": [
{
"message": "name is too long, the max length is 20 characters",
"path": [
"checkName"
],
"extensions": {
"code": "INPUT_VALIDATION_ERROR"
}
}
],
"data": null
}
Example B "Errors hidden":
Query
mutation inviteByEmail {
invite(email: "invalid!!!~~~test!--#example.com") {
status
}
}
Response from remote service (httpLink)
response.errors and graphQLErrors in onError method also contains the error
{
"errors": [
{
"message": "Email not valid",
"path": [
"invite"
],
"extensions": {
"code": "INPUT_VALIDATION_ERROR"
}
}
],
"data": {
"invite": {
"status": null
}
}
}
Response
{
"data": {
"invite": {
"status": null
}
}
}
According to graphql spec I would have expected the errors object to not be hidden if it is part of the response
https://graphql.github.io/graphql-spec/June2018/#sec-Errors
If the data entry in the response is present (including if it is the value null), the errors entry in the response may contain any errors that occurred during execution. If errors occurred during execution, it should contain those errors.

get row from AWS dynamoDB table with cognito authentication

I have AWS dynamo DB table where I store information for AWS Cognito users. I created the table to be private so that only the owner of a row in the table can read/write the data (based on cognito authentication). I need to get the data for the user through a lambda function. I created the IAM role for the function in this way:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:XX-XXXX-X:XXXXXXX:table/tablename"
],
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": [
"${cognito-identity.amazonaws.com:sub}"
]
}
}
}
]
}
In the lamba function (node.js) I need to get the information stored from the user so I call:
let ddb = new AWS.DynamoDB({ apiVersion: 'latest' });
var params = {
TableName: tablename,
Key: { 'id': {S: event.queryStringParameters.user_id}
}
};
ddb.getItem(params, function(err, data) {
if (err) {
console.log("Error", err);
}
else {
console.log("Success", data);
}
});
I get the error:
Error { AccessDeniedException: User: arn:aws:sts::xxxxxx:assumed-role/lambda_dynamo/getPmtDetails is not authorized to perform: dynamodb:GetItem on resource
How can I call getItem with the cognito id in order to retrive the row that belong to the user?

Spring Boot Swagger annotations for supporting API KEYs on AWS API Gateway

I am trying to setup an AWS API Gateway that requires an API KEY in the header of any request. I setup swagger to generate the json definition and AWS imports it perfectly fine. However when I try to add the API KEY Security definition, Amazon rejects my swagger api doc with this error:
Your API was not imported due to errors in the Swagger file.
API Key security definition 'api_key' has unexpected name or location. Ignoring.
I assume i'm doing it wrong...so i've tried several variations along these lines.
given a spring boot config created using springfox thusly:
#Bean
public Docket swaggerSpringMvcPlugin() {
List<ApiKey> securitySchemes = new ArrayList<>();
ApiKey apiKey = new ApiKey("apiKey", "api_key", "header");
list.add(apiKey);
//the above is probably where i'm missing something
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.apiInfo(apiInfo())
.securitySchemes(securitySchemes)
.select()
.paths(PathSelectors.regex("/api/swaggertest"))
.build();
}
and the above api defined like so:
#RestController
public class SwaggerTestController {
#ApiOperation(notes = "my notes", value = "test", nickname = "testNickname",
tags = {"tests"}, authorizations = {#Authorization(value="api_key")} )
#ApiResponses({
#ApiResponse(code = 200, message = "Nice!", response = Swag.class)
})
#RequestMapping(value = "/api/swaggertest", method = RequestMethod.GET, produces = "application/json")
public ResponseEntity<Swag> getSwag() throws Exception {
return ResponseEntity.ok().body(new Swag());
}
}
When i run my app the api-docs produce (i remove some sections to keep it smaller):
{
swagger: "2.0",
host: "localhost:4014",
basePath: "/",
tags: [
{
name: "swagger-test-controller",
description: "Swagger Test Controller"
}
],
paths: {
/api/swaggertest: {
get: {
tags: [
"tests"
],
summary: "test",
description: "my notes",
operationId: "testNickname",
consumes: [
"application/json"
],
produces: [
"application/json"
],
responses: {
200: {
description: "Nice!",
schema: {
$ref: "#/definitions/Swag"
}
}
},
security: [
{
api_key: [ ]
}
]
}
}
},
securityDefinitions: {
api_key: {
type: "apiKey",
name: "api_key",
in: "header"
}
},
definitions: {
Swag: {
type: "object",
properties: {
foo: {
type: "string"
}
}
}
}
if anyone can help point me to how to add api key support to this, i'd appreciate it.
Security definition should look like this, referencing <any_name> in your method security.
"<any_name>" : {
"type" : "apiKey",
"name" : "x-api-key",
"in" : "header"
},

Resources