Issue
I am trying to connect to a cluster using the last example from mongoose site
Here are my files using node14 and typescript
- src/index.ts
import { APIGatewayProxyHandler } from "aws-lambda"
export { list as productsList } from "./products"
export const list: APIGatewayProxyHandler = (event, context, callback) => {
callback(null, {
statusCode: 200,
body: `Hello from ${process.env.AWS_SAM_BRANCH}`,
})
}
- src/utils.ts
import mongoose from "mongoose"
import { APIGatewayProxyResult, Callback } from "aws-lambda"
let mongoConnection: Promise<typeof mongoose> | null = null
export const connectMongoose = async () => {
if (mongoConnection == null) {
const mongoURI = `mongodb+srv://USER:[email protected]/myFirstDB?retryWrites=true&w=majority`
mongoConnection = mongoose
.connect(mongoURI, { serverSelectionTimeoutMS: 3000 })
.then((mongooseReply) => {
console.log({ mongooseReply })
return mongoose
})
.catch((mongooseError) => {
console.log({ mongooseError })
return mongoose
})
await mongoConnection
}
return mongoConnection
}
export const errorHandler = (error: unknown, callback: Callback<APIGatewayProxyResult>) => {
console.error("catchedError", error)
if (error instanceof Error) {
callback(null, {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: error.message }),
})
} else {
callback(null, {
statusCode: 500,
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ error: "Internal server error" }),
})
}
}
- src/products/index.ts
import { APIGatewayProxyHandler } from "aws-lambda"
import Model from "./model"
import { connectMongoose, errorHandler } from "../utils"
export const list: APIGatewayProxyHandler = (event, context, callback) => {
try {
connectMongoose()
Model.find({}, (error: unknown, reply: unknown) => {
if (error) throw error
callback(null, {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(reply),
})
})
} catch (error) {
errorHandler(error, callback)
}
}
- src/products/model.ts
import mongoose from "mongoose"
const model = mongoose.model(
"Product",
new mongoose.Schema(
{
title: {
type: String,
required: true,
maxLength: 256,
},
description: {
type: String,
required: true,
maxLength: 2048,
},
count: {
type: Number,
required: true,
min: 0,
max: 1000 * 1000,
},
},
{
timestamps: true,
versionKey: false,
}
)
)
export default model
Here is the code in a repo is includes commands used to deploy with AWS SAM
There are 2 routes in my app
This works and returns Hello from test
with status 200
This doesn’t work and returns {"message":"Internal Server Error"}
with status 500
Here are the CloudWatch logs exported as CSV
timestamp,message
1647203544609,"START RequestId: 83fd3fc8-1134-4ff4-a5f7-7e83a65159ce Version: $LATEST
"
1647203545742,"2022-03-13T20:32:25.685Z 83fd3fc8-1134-4ff4-a5f7-7e83a65159ce INFO {
mongooseReply: <ref *1> Mongoose {
connections: [ [NativeConnection] ],
models: { Product: Model { Product } },
events: EventEmitter {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
[Symbol(kCapture)]: false
},
options: {
pluralization: true,
autoIndex: true,
autoCreate: true,
[Symbol(mongoose:default)]: true
},
_pluralize: [Function: pluralize],
Schema: [Function: Schema] {
reserved: [Object: null prototype],
Types: [Object],
ObjectId: [Function]
},
model: [Function (anonymous)],
plugins: [ [Array], [Array], [Array], [Array], [Array], [Array] ],
default: [Circular *1],
mongoose: [Circular *1]
}
}
"
1647203549616,"END RequestId: 83fd3fc8-1134-4ff4-a5f7-7e83a65159ce
"
1647203549616,"REPORT RequestId: 83fd3fc8-1134-4ff4-a5f7-7e83a65159ce Duration: 5005.75 ms Billed Duration: 5000 ms Memory Size: 128 MB Max Memory Used: 76 MB Init Duration: 366.30 ms
"
1647203549616,"2022-03-13T20:32:29.616Z 83fd3fc8-1134-4ff4-a5f7-7e83a65159ce Task timed out after 5.01 seconds
"
Solution
As explained in this GitHub issue
A few suggestions:
- You should either choose between a full callback approach and a full promise approach
- Don’t mix async / await with .then syntax when you can avoid it
import mongoose from "mongoose"
import { APIGatewayProxyHandler } from "aws-lambda"
let mongoConnection: Promise<typeof mongoose> | null = null
const connectMongoose = async () => {
if (mongoConnection == null) {
const mongoURI = `mongodb+srv://YOUR_CLUSTER_URL`
mongoConnection = mongoose
.connect(mongoURI, { serverSelectionTimeoutMS: 3000 })
.then((mongooseReply) => {
console.log({ mongooseReply })
return mongoose
})
.catch((mongooseError) => {
console.log({ mongooseError })
return mongoose
})
await mongoConnection
}
return mongoConnection
}
const Model = mongoose.model(
"Product",
new mongoose.Schema(
{
title: String,
description: String,
},
{
timestamps: true,
versionKey: false,
}
)
)
export const myRoute: APIGatewayProxyHandler = async (event, context) => {
try {
await connectMongoose();
const reply = await Model.find({}).exec();
return {
statusCode: 200,
headers: { "Content-Type": "application/json" },
body: JSON.stringify(reply),
};
} catch (error) {
return {
statusCode: 400,
headers: { "Content-Type": "application/json" },
body: "Server error",
};
}
}
Answered By – Luis Marroquin
Answer Checked By – Candace Johnson (BugsFixing Volunteer)