How to deploy a graphql api built with express to AWS serverless? - amazon-web-services

I have been trying to deploy a backend api service made with graphql api and express to Amazon web services. This is my folder structure
Graphql-api
-src
-index.js
-serverless.yml
-index.js(this only contains an import statement of the src folder)
The serverless.yml looks like this
service: graphql-api
provider:
name: aws
runtime: nodejs12.x
lambdaHashingVersion: 20201221
functions:
api:
handler: src/index.handler
events:
- http:
path: graphql
method: ANY
cors: true
And I have exported this handler in my src/index.js file
`const awsServerlessExpress = require('aws-serverless-express');
const app = require('./app');
const server = awsServerlessExpress.createServer(app);
exports.handler = (event, context) => awsServerlessExpress.proxy(server, event, context);`
But when I run serverless deploy and get the endpoint url which is: https://nir4749aal.execute-api.us-east-1.amazonaws.com/dev/graphql
I get a message saying internal server error. I can't figure out what I am doing wrong. This is my first time trying to deploy to AWS. Any help or suggestion would help thanks in advance.
-----UPDATE--------
This are the logs from lambda
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Cannot use import statement outside a module",
"stack": [
"Runtime.UserCodeSyntaxError: SyntaxError: Cannot use import statement outside a module",
" at _loadUserApp (/var/runtime/UserFunction.js:98:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:140:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:30)",
" at Module._compile (internal/modules/cjs/loader.js:1015:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1035:10)",
" at Module.load (internal/modules/cjs/loader.js:879:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:724:14)",
" at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)",
" at internal/main/run_main_module.js:17:47"
]
}

Related

Lambda works locally, but not when deployed

I'm using serverless framework and my endpoint work locally with sls offline, but when I sls deploy it to AWS I get 502 Bad Gateway in postman
and if I go to AWS Lambda console and click test event to see what comes up I get
{
"errorType": "Runtime.UserCodeSyntaxError",
"errorMessage": "SyntaxError: Unexpected token '??='",
"trace": [
"Runtime.UserCodeSyntaxError: SyntaxError: Unexpected token '??='",
" at _loadUserApp (/var/runtime/UserFunction.js:222:13)",
" at Object.module.exports.load (/var/runtime/UserFunction.js:300:17)",
" at Object.<anonymous> (/var/runtime/index.js:43:34)",
" at Module._compile (internal/modules/cjs/loader.js:1085:14)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)",
" at Module.load (internal/modules/cjs/loader.js:950:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:790:12)",
" at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:75:12)",
" at internal/main/run_main_module.js:17:47"
]
}
There's nothing in my code that has ??=' in it so I made my endpoint super simple as a process of elimination and returned a response instantly ie
router.get('/my-api', async (req, res: Response) => {
return res.status(200).json({"message": "success"});
});
but I still get the same error.
serverless.yaml
service: my-service
plugins:
- serverless-webpack
- serverless-offline
custom:
env:
default: Sandbox
prod: Production
AWS_REGION: us-east-1
apigwBinary:
types: #list of mime-types
- '*/*'
contentCompression: 14000
webpack:
webpackConfig: ./webpack.config.js
packager: 'npm'
includeModules:
forceExclude:
- aws-sdk
- dotenv
provider:
name: aws
versionFunctions: false
region: ${opt:region, 'us-east-1'}
stage: ${opt:stage, 'staging'}
environment:
STAGE: ${self:provider.stage}
functions:
myApi:
handler: src/handler.service
events:
- http:
path: route/my-api
method: GET
cors: true
handler.ts
import { APIGatewayProxyEvent, Context, ProxyResult } from 'aws-lambda';
import awsServerlessExpress from 'aws-serverless-express';
import app from './app';
const server = awsServerlessExpress.createServer(app);
export function service(event: APIGatewayProxyEvent, context: Context) {
return awsServerlessExpress.proxy(server, event, context);
}
So as a recap, it works locally, but not after sls deploy in AWS in postman or aws console lambda test event. So if it works locally, why isn't it working in aws. I appreciate any help!

Why AWS Lambda is not updating though GitLab CI / CD Pipeline get a green checkmark

Following this tutorial, https://docs.gitlab.cn/14.0/ee/user/project/clusters/serverless/aws.html#serverless-framework
Created a function in AWS Lambda called create-promo-animation
Created a /src/handler.js
"use strict";
module.exports.hello = async (event) => {
return {
statusCode: 200,
body: JSON.stringify(
{
message: "Your function executed successfully!",
},
null,
2
),
};
};
Created gitlab-ci.yml
stages:
- deploy
production:
stage: deploy
before_script:
- npm config set prefix /usr/local
- npm install -g serverless
script:
- serverless deploy --stage production --verbose
environment: production
Created serverless.yml
service: gitlab-example
provider:
name: aws
runtime: nodejs14.x
functions:
create-promo-animation:
handler: src/handler.hello
events:
- http: GET hello
pushed to GitLab, Pipe run well
But code is not updating in AWS, why?

Amplify GraphQL No Credentials Error in NextJs Application

NextJs Application is working perfectly fine locally but after pushing the fronted to AWS I'm getting the run time error, No Credentials in callback.js api
No Build time error, so I assume aws-exports.js file is built correctly during the build but I don't know if it is built with the required details like API key on AWS.
I'm using API key authentication by default. I'm not using amplify add auth because I've a requirement to use custom auth. I know amplify auth is the recommend way but I still need to use my custom method.
I have already tried multiple suggestions like disable Analytics: true as suggested in couple of other discussions but none of them worked for me. Build my project multiple times from scratch by re-installing all the dependencies but no luck.
callback.js API
import { API, graphqlOperation } from 'aws-amplify';
import {getAuth} from "../../../../src/graphql/queries"
import {createAuth} from "../../../../src/graphql/mutations"
export default async function callback(req, res) {
const record = await API.graphql(graphqlOperation(getAuth, {emailId: "abc#gmail.com"}))
res.status(200).json({ record });
}
aws-exports.js
/* eslint-disable */
// WARNING: DO NOT EDIT. This file is automatically generated by AWS Amplify. It will be overwritten.
const awsmobile = {
"aws_project_region": "us-east-1",
"aws_appsync_graphqlEndpoint": "https://dummyUrl.appsync-api.us-east-1.amazonaws.com/graphql",
"aws_appsync_region": "us-east-1",
"aws_appsync_authenticationType": "API_KEY",
"aws_appsync_apiKey": "da2-************"
};
export default awsmobile;
_app.js
import {Amplify} from 'aws-amplify';
import config from "../aws-exports"
Amplify.configure(config)
function MyApp({ Component, pageProps: { session, ...pageProps } }) {
// App logic
})
GraphQL Schema
type Auth #model #auth(rules: [{ allow: public }]) {
emailId: ID! #primaryKey
name: String
screen_name: String
profile_img: String
userSession: String
tokenType: String
accessToken: String
accessSecret: String
refreshToken: String
accessScope: String
}
Package.json
"dependencies": {
"#emoji-mart/data": "^1.0.6",
"#emoji-mart/react": "^1.0.1",
"aes256": "^1.1.0",
"aws-amplify": "^4.3.37",
"emoji-mart": "^5.2.2",
"formidable": "^2.0.1",
"js-cookie": "^3.0.1",
"next": "12.3.1",
"react": "18.2.0",
"react-datepicker": "^4.8.0",
"react-dom": "18.2.0",
},
Amplify.yml
version: 1
backend:
phases:
build:
commands:
- '# Execute Amplify CLI with the helper script'
- amplifyPush --simple
frontend:
phases:
preBuild:
commands:
- yarn install
build:
commands:
- yarn run build
artifacts:
baseDirectory: .next
files:
- '**/*'
cache:
paths:
- node_modules/**/*
Edited
I've found how the server side process work with amplify and graphql. Please refer to this. On the server side, you need to pass the API KEY explicitly into the graphql request as that page writes.
==========
I'm using appsync, but appsync pure directives. So just let me provide the reference below. Please confirm the rule follows this way.
{ allow: public, provider: apiKey }

503: Service Unavailable AWS Lambda with Github Probot

I'm trying to receive webhooks from Github using a probot application, but every single time I try this, I get a {"message":"Service Unavailable"} error.
Github sends this payload to an AWS Lambda function, and by googling (i think) this is an issue with not having enough nodes to handle the number of requests.
Either something is wrong with my code or there is an error with the configuration.
I'm using the serverless framework to upload to AWS lambda.
Here is the part where the code fails (no error messages in logs, and the bot just quits):
const yamlFile = async (context) => {
try {
console.log("trying to get yaml")
var yamlfile = await context.octokit.repos.getContent({
owner: context.payload.repository.owner.login,
repo: context.payload.repository.name,
path: ".bit/config.yml",
});
console.log(yamlfile)
} catch (e) {
console.log("Error with getting content of yaml");
console.log(e)
return null
}
console.log("got yaml, but no content yet");
yamlfile = Buffer.from(yamlfile.data.content, 'base64').toString()
console.log(yamlfile)
try {
let fileContents = yamlfile
configyml = yaml.load(fileContents);
} catch (e) {
const issueBody = context.issue({
title: "[ERROR] Please read",
body: `There was an issue parsing the config file of this course. Please contact your counselor and send them the below error.\n${e}`,
});
context.octokit.issues.create(issueBody)
console.log("ERROR: " + e);
return null
}
console.log("returining configyml")
return configyml;
}
The function yamlFile() is being called in our main function here:
let currentStep = ""
let configData = await data.yamlFile(context);
console.log(configData)
if (configData == null) {
console.log("null config data");
return
}
AWS Config
Timeout: 60 seconds
serverless.yml for Serverless framework:
service: <SERVICE NAME>
# app and org for use with dashboard.serverless.com
app: <APP NAME>
org: <ORG NAME>
frameworkVersion: "2"
useDotenv: true
provider:
name: aws
runtime: nodejs12.x
lambdaHashingVersion: 20201221
environment:
APP_ID: ${param:APP_ID}
PRIVATE_KEY: ${param:PRIVATE_KEY}
WEBHOOK_SECRET: ${param:WEBHOOK_SECRET}
NODE_ENV: production
LOG_LEVEL: debug
memorySize: 2048
functions:
webhooks:
handler: handler.webhooks
memorySize: 2048
events:
- httpApi:
path: /api/github/webhooks
method: post

Creation of CfnWebACL for rate based rule fails (AWS CDK WAF Regional)

I am trying to setup a rate based rule using AWS CDK (#aws-cdk/aws-wafregional v1.4.0).
This is my very simple JavaScript-setup:
const cdk = require('#aws-cdk/core');
const waf = require('#aws-cdk/aws-wafregional');
class TstStack extends cdk.Stack {
constructor(scope, id, props) {
super(scope, id, props);
const rule = new waf.CfnRateBasedRule(this, 'rule', {
metricName: `rateRule`,
name: 'rate-rule',
rateKey: 'IP',
rateLimit: 2010
});
const acl = new waf.CfnWebACL(this, 'acl', {
defaultAction: { type: 'ALLOW' },
metricName: 'rateAcl',
name: 'rate-acl',
rules: [{
action: { type: 'BLOCK' },
priority: 1,
ruleId: rule.ref
}]
});
}
}
module.exports = { TstStack }
To create the rule is no problem. But the stack creation fails on the Web ACL. The error message is:
The referenced item does not exist. (Service: AWSWAFRegional; Status Code: 400; Error Code: WAFNonexistentItemException
What am I missing here, why is it not possible to create the CfnWebACL-object?
For reference, the complete output:
3/4 | 9:49:31 PM | CREATE_FAILED | AWS::WAFRegional::WebACL | acl The referenced item does not exist. (Service: AWSWAFRegional; Status Code: 400; Error Code: WAFNonexistentItemException; Request ID: e4d897ef-c138-11e9-bf23-fb4702c5a89a)
new TstStack (/app/infrastructure/apps/tst/lib/tst-stack.js:16:21)
\_ Object.<anonymous> (/app/infrastructure/apps/tst/bin/tst.js:9:1)
\_ Module._compile (internal/modules/cjs/loader.js:778:30)
\_ Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
\_ Module.load (internal/modules/cjs/loader.js:653:32)
\_ tryModuleLoad (internal/modules/cjs/loader.js:593:12)
\_ Function.Module._load (internal/modules/cjs/loader.js:585:3)
\_ Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
\_ startup (internal/bootstrap/node.js:283:19)
\_ bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)
This aggravated me for a while also. I finally saw the following in the CloudFormation documentation for the rate-rules:
Note you can only create rate-based rules using a CloudFormation template. To add the rate-based rules created through CloudFormation to a web ACL, use the AWS WAF console, API, or command line interface (CLI). For more information, see UpdateWebACL.
Basically, you can create the rule, but you can't associate it with an ACL through AWS CloudFormation.