MongoServerError: BSON field 'insert.jsonSchema' is an unknown field - node.js

I am new in MongoDB. I want to do client side field level encryption.
Here is the full project link which one I am practicing:
https://javascript.plainenglish.io/mongodb-client-side-field-level-encryption-csfle-for-beginners-5eed965d4ba3
Requirments: What I have Installed.
MongoDB Enterprise server 6.0,
npm i mongodb-client-encryption uuid-base64 mongodb
I am getting this error when running node app.js
app.js
const fs = require("fs");
const mongodb = require("mongodb");
const { MongoClient, Binary } = mongodb;
const base64KeyId = "fFGm1x/fRIWlWPLWhvf1Ig==";
const buffer = Buffer.from(base64KeyId, "base64");
const keyIdBinary = new Binary(buffer, Binary.SUBTYPE_UUID);
const JSONSchemaCreator = require("./schema-creator");
const jsonSchemas = JSONSchemaCreator(keyIdBinary);
const connectionString = "mongodb://localhost:27017/";
const keyVaultNamespace = "encryption.__keyVault";
const path = "./master-key.txt";
const localMasterKey = fs.readFileSync(path);
const kmsProviders = {
local: {
key: localMasterKey,
},
};
const patientSchema = {
"medicalRecords.patients": jsonSchemas,
};
const extraOptions = {
mongocryptdURI: "mongodb://localhost:27020",
};
const secureClient = new MongoClient(connectionString, {
useNewUrlParser: true,
useUnifiedTopology: true,
autoEncryption: {
keyVaultNamespace,
kmsProviders,
schemaMap: patientSchema,
extraOptions: extraOptions,
},
});
async function insertPatient(name, bloodType, ssn) {
try {
await secureClient.connect();
const keyDB = secureClient.db("medicalRecords");
const collection = keyDB.collection("patients");
const writeResult = await collection.insertOne({
name,
ssn,
bloodType,
});
console.log(writeResult);
} catch (writeError) {
console.error("writeError occurred:", writeError);
}
}
insertPatient(
'Jon Doe',
"O+",
'1234567',
);
all of my server connection is perfect.
**
error:**
writeError occurred: MongoServerError: BSON field 'insert.jsonSchema' is an unknown field. This command may be meant for a mongocryptd process.
at Connection.onMessage (/home/shahed/Documents/encryptionDemo/node_modules/mongodb/lib/cmap/connection.js:230:30)
at MessageStream.<anonymous> (/home/shahed/Documents/encryptionDemo/node_modules/mongodb/lib/cmap/connection.js:61:60)
at MessageStream.emit (node:events:513:28)
at processIncomingData (/home/shahed/Documents/encryptionDemo/node_modules/mongodb/lib/cmap/message_stream.js:125:16)
at MessageStream._write (/home/shahed/Documents/encryptionDemo/node_modules/mongodb/lib/cmap/message_stream.js:33:9)
at writeOrBuffer (node:internal/streams/writable:392:12)
at _write (node:internal/streams/writable:333:10)
at Writable.write (node:internal/streams/writable:337:10)
at Socket.ondata (node:internal/streams/readable:766:22)
at Socket.emit (node:events:513:28) {
ok: new Double(0.0),
code: new Int32(4662500),
codeName: 'Location4662500',
[Symbol(errorLabels)]: Set(0) {}
}
Please help me out and thanks in advance
I have a jsonschema format which one need create and perform encryption push into db
schema-creator.js
module.exports = function (keyId) {
return {
bsonType: "object",
encryptMetadata: {
keyId,
},
properties: {
bloodType: {
encrypt: {
bsonType: "string",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Random",
},
},
ssn: {
encrypt: {
bsonType: "int",
algorithm: "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic",
},
},
},
};
};

Related

How can I add dig into errors on grahpql subscription over websocket?

I setup a graphql server and client by Apollo in nodejs. The server will serve one http link for query and mutation and one websocket link for subscription.
When I run the code, query and mutation works fine but subscription doesn't work. The server doesn't see any subscription request but the client doesn't throw any errors.
I am not sure what I am doing is wrong. How can I see detailed information on websocket layer?
Server code:
const { ApolloServer } = require('#apollo/server');
const { makeExecutableSchema } = require('#graphql-tools/schema');
const { createServer } = require('http');
const express = require('express');
const { WebSocketServer } = require('ws');
const { ApolloServerPluginDrainHttpServer } = require('#apollo/server/plugin/drainHttpServer');
const { useServer } = require('graphql-ws/lib/use/ws');
const cors = require('cors');
const bodyParser = require('body-parser');
const { expressMiddleware } = require('#apollo/server/express4');
const { PubSub } = require('graphql-subscriptions');
const typeDefs = `#graphql
type Book {
title: String
author: String
}
input BookInput {
title: String
author: String
}
type Query {
books: [Book]
}
type Subscription {
bookCreated: Book
}
type Mutation {
postBook(input: BookInput): ID!
}
`;
const pubsub = new PubSub();
const resolvers = {
Query: {
books: () => [
{
title: 'hello',
author: 'joey',
},
],
},
Subscription: {
bookCreated: {
subscribe: () => {
console.log('receive subscribe');
pubsub.asyncIterator(['POST_CREATED']);
},
},
},
Mutation: {
postBook: async (book) => {
console.log('postBook', book)
await pubsub.publish('POST_CREATED', {
postCreated: {
title: 'Ali Baba',
author: 'Open sesame',
},
});
return '001';
},
},
};
const schema = makeExecutableSchema({ typeDefs, resolvers });
const app = express();
const httpServer = createServer(app);
const wsServer = new WebSocketServer({
server: httpServer,
path: '/graphql',
});
const serverCleanup = useServer({ schema }, wsServer);
const server = new ApolloServer({
schema,
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
{
async serverWillStart() {
return {
async drainServer() {
await serverCleanup.dispose();
},
};
},
},
],
});
server.start().then((d) => {
console.log('started', d);
app.use('/graphql', cors(), bodyParser.json(), expressMiddleware(server));
});
httpServer.listen(4000, () => {
console.log(`Server is now running on http://localhost:4000/graphql`);
});
client code:
const { ApolloClient } = require('apollo-client');
const { InMemoryCache } = require('apollo-cache-inmemory');
const gql = require('graphql-tag');
const { createHttpLink } = require('apollo-link-http');
const ws = require('ws');
const { SubscriptionClient } = require('subscriptions-transport-ws');
const { WebSocketLink } = require('apollo-link-ws');
const fetch = require('node-fetch');
const httpLink = createHttpLink({
uri: `http://localhost:4000/graphql`,
fetch,
});
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});
const wsLink = new WebSocketLink(
new SubscriptionClient(
'ws://localhost:4000/graphql',
{
reconnect: true,
},
ws,
[]
)
);
const wsclient = new ApolloClient({
link: wsLink,
cache: new InMemoryCache(),
});
client
.query({
query: gql`
query books {
books {
author
}
}
`,
})
.then((result) => console.log(JSON.stringify(result, null, 2)));
wsclient
.subscribe({
query: gql`
subscription bookCreated {
bookCreated {
author
}
}
`,
})
.subscribe({
next: (d) => {
console.log('subscirbe', d);
},
error: (err) => console.error(err),
});
setTimeout(() => {
client
.mutate({
mutation: gql`
mutation postBook {
postBook(input: { author: "aa", title: "title" })
}
`,
})
.then((d) => console.log('mutate:', d))
.catch(console.error);
}, 1000);

DiscordJS v14 - Command Handler

I'm trying to create a command handle function, and this is my code, however it gives me an error in the console.
Sometimes when I go and reload the bot, the error doesn't populate, but it won't show the slash command. Other times, I get the error listed below.
const chalk = require("chalk");
const fs = require("fs");
const { REST } = require('#discordjs/rest');
const { Routes } = require('discord-api-types/v9');
module.exports = (client) => {
client.handleCommands = async () => {
const commandFolders = fs.readdirSync("./src/commands");
for (const folder of commandFolders) {
const commandFiles = fs
.readdirSync(`./src/commands/${folder}`)
.filter((file) => file.endsWith(".js"));
const { commands, commandArray } = client;
for (const file of commandFiles) {
const command = require(`../../commands/${folder}/${file}`);
commands.set(command.data.name, command);
commandArray.push(command, command.data.toJSON());
console.log(
chalk.white("Command: ") +
chalk.cyan.bold`${command.data.name} ` +
chalk.white("has successfully loaded.")
);
}
}
const clientId = "(Client_ID)";
const rest = new REST({ version: "10" }).setToken(
process.env.DISCORD_DEV_TOKEN
);
try {
console.log("Started refreshing application (/) commands.");
await rest.put(Routes.applicationCommands(clientId), {
body: client.commandArray,
});
console.log("Successfully reloaded application (/) commands.");
} catch (error) {
console.error(error);
}
};
};
Here's the error.
DiscordAPIError[50035]: Invalid Form Body
0.name[BASE_TYPE_REQUIRED]: This field is required
at SequentialHandler.runRequest (/home/**/Discord Bot/node_modules/#discordjs/rest/dist/index.js:659:15)
at processTicksAndRejections (node:internal/process/task_queues:96:5)
at async SequentialHandler.queueRequest (/home/**/Discord Bot/node_modules/#discordjs/rest/dist/index.js:458:14)
at async REST.request (/home/**/Discord Bot/node_modules/#discordjs/rest/dist/index.js:902:22)
at async Client.client.handleCommands (/home/**/Discord Bot/src/functions/handlers/handleCommands.js:35:7) {
requestBody: { files: undefined, json: [ [Object], [Object] ] },
rawError: {
code: 50035,
errors: { '0': [Object] },
message: 'Invalid Form Body'
},
code: 50035,
status: 400,
method: 'PUT',
url: 'https://discord.com/api/v10/applications/(Client_ID)/commands'
}
I've attempted to debug it and follow the documentation from the Discord.JS website, but that doesn't even resolve the issue.
I currently have just the typical ping command, and here's the code for that.
const { SlashCommandBuilder } = require("discord.js");
module.exports = {
data: new SlashCommandBuilder()
.setName("ping")
.setDescription("Return's the bot's ping!"),
async execute(interaction, client) {
const message = await interaction.deferReply({
fetchReply: true,
});
const newMessage = `API Latency: ${client.ws.ping}\n Client Ping: ${
message.createdTimestamp - interaction.createdTimestamp
}`;
await interaction.editReply({
content: newMessage,
});
},
};
Is anyone able to share where I'm making the mistake?
Turns out my issue was within commandArray.push.
I had it written out as
commandArray.push(command, command.data.toJSON());
When it needed to be
commandArray.push(command.data.toJSON());

Mongodb Typescript UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'conn' of undefined at Object.connectToDatabase [as default]

typescript connection to mongo database throws error , it can read conn of undefined after conn has been declared globally
UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'conn' of undefined
at Object.connectToDatabase [as default]
import { MongoClient, Db } from "mongodb";
import config from "../config/config";
const { dbName, mongoDBUri } = config;
type MongoConnection = {
client: MongoClient;
db: Db;
};
declare global {
namespace NodeJS {
interface Global {
mongodb: {
conn: MongoConnection | null;
promise: Promise<MongoConnection> | null;
};
}
}
}
let cached = global.mongodb;
async function connectToDatabase() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
};
cached.promise = MongoClient.connect(mongoDBUri as string, opts).then(
(client) => {
return {
client,
db: client.db(dbName),
};
}
);
}
cached.conn = await cached.promise;
return cached.conn;
}
export default connectToDatabase;
You can use the below setup
//interfaces/db.interface
export interface dbConfig {
host: string;
port: number;
database: string;
username: string;
password: string;
}
//database.ts
import { dbConfig } from "#interfaces/db.interface";
const { host, port, database, username, password }: dbConfig = config.get("dbConfig");
export const dbConnection = {
url: `mongodb://${username}:${password}#${host}:${port}/${database}?authSource=admin`,
options: {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
useCreateIndex: true
},
};
//app.ts (express app)
import { dbConnection } from "#databases";
constructor(routes: Routes[]) {
this.app = express();
this.port = process.env.PORT || 5000;
this.env = process.env.NODE_ENV || "development";
this.connectToDatabase();
}
private connectToDatabase() {
if (this.env !== "production") {
set("debug", true);
}
connect(dbConnection.url, dbConnection.options)
.catch((error) =>
console.log(`${error}`)
);
}
Here I am assuming you have the setup of paths in the tsconfig.json file so that # will work in imports.
After several times of trying, I had to use the NextJs MongoDB connection pattern and convert it to typescript and it worked perfectly fine
import config from "./../config/config";
import { MongoClient, Db } from "mongodb";
const { dbName, mongoDBUri } = config;
if (!mongoDBUri) {
throw new Error(
"Define the mongoDBUri environment variable inside .env"
);
}
if (!dbName) {
throw new Error(
"Define the dbName environment variable inside .env"
);
}
type MongoConnection = {
client: MongoClient;
db: Db;
};
declare global {
namespace NodeJS {
interface Global {
mongodb: {
conn: MongoConnection | null;
promise: Promise<MongoConnection> | null;
};
}
}
}
let cached = global.mongodb;
if (!cached) {
cached = global.mongodb = { conn: null, promise: null };
}
export default async function connectToDatabase() {
if (cached.conn) {
return cached.conn;
}
if (!cached.promise) {
console.log("Establishing new database connection");
const opts = {
useNewUrlParser: true,
useUnifiedTopology: true,
};
cached.promise = MongoClient.connect(mongoDBUri as string, opts).then(
(client) => {
return {
client,
db: client.db(dbName),
};
}
);
}
cached.conn = await cached.promise;
return cached.conn;
}

How to solve 'missing setcode.vmtype (type=uint8)' error when deploying EOS Smart Contract using eosjs?

I'm trying to deploy an EOS Smart Contract using eosjs.
I referred the code from https://eosio.github.io/eosjs/latest/how-to-guides/how-to-deploy-a-smart-contract
const wasmFilePath = './hello.wasm'
const abiFilePath = './hello.abi'
const fs = require('fs')
const { Api, JsonRpc, Serialize } = require('eosjs');
const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig'); // development only
const fetch = require('node-fetch'); //node only
const { TextDecoder, TextEncoder } = require('util'); //node only
let privateKey1 = '5J***********'
const privateKeys = [privateKey1];
const signatureProvider = new JsSignatureProvider(privateKeys);
const rpc = new JsonRpc('https://jungle2.cryptolions.io:443', { fetch }); //required to read blockchain state
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
const buffer = new Serialize.SerialBuffer({
textEncoder: api.textEncoder,
textDecoder: api.textDecoder,
})
let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
const abiDefinitions = api.abiTypes.get('abi_def')
abiJSON = abiDefinitions.fields.reduce(
(acc, { name: fieldName }) =>
Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
abiJSON
)
abiDefinitions.serialize(buffer, abiJSON)
let serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
deployContract();
async function deployContract(){
try{
const wasmFilePath = './hello.wasm'
const abiFilePath = './hello.abi'
const fs = require('fs')
const { Api, JsonRpc, Serialize } = require('eosjs');
const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig'); // development only
const fetch = require('node-fetch'); //node only
const { TextDecoder, TextEncoder } = require('util'); //node only
let privateKey1 = '5J***********'
const privateKeys = [privateKey1];
const signatureProvider = new JsSignatureProvider(privateKeys);
const rpc = new JsonRpc('https://jungle2.cryptolions.io:443', { fetch }); //required to read blockchain state
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
const buffer = new Serialize.SerialBuffer({
textEncoder: api.textEncoder,
textDecoder: api.textDecoder,
})
let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
const abiDefinitions = api.abiTypes.get('abi_def')
abiJSON = abiDefinitions.fields.reduce(
(acc, { name: fieldName }) =>
Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
abiJSON
)
abiDefinitions.serialize(buffer, abiJSON)
let serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
deployContract();
async function deployContract(){
try{
await api.transact(
{
actions: [
{
account: 'eosio',
name: 'setcode',
authorization: [
{
actor: user_name,
permission: 'active',
},
],
data: {
account: user_name,
code: wasmHexString,
},
},
{
account: 'eosio',
name: 'setabi',
authorization: [
{
actor: user_name,
permission: 'active',
},
],
data: {
account: user_name,
abi: serializedAbiHexString,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
}
)
}
catch(e){
console.log(e)
}
};
};
I'm getting the following error:
PS E:\EOSIO\smartcontract> node .\deploySmartContract.js
Error: missing setcode.vmtype (type=uint8)
at Object.serializeStruct [as serialize] (E:\EOSIO\node_modules\eosjs\dist\eosjs-serialize.js:571:27)
at serializeActionData (E:\EOSIO\node_modules\eosjs\dist\eosjs-serialize.js:1041:12)
at Object.serializeAction (E:\EOSIO\node_modules\eosjs\dist\eosjs-serialize.js:1051:15)
at Api. (E:\EOSIO\node_modules\eosjs\dist\eosjs-api.js:278:71)
at step (E:\EOSIO\node_modules\eosjs\dist\eosjs-api.js:47:23)
at Object.next (E:\EOSIO\node_modules\eosjs\dist\eosjs-api.js:28:53)
at fulfilled (E:\EOSIO\node_modules\eosjs\dist\eosjs-api.js:19:58)
at process._tickCallback (internal/process/next_tick.js:68:7)
const wasmFilePath = './hello.wasm'
const abiFilePath = './hello.abi'
const fs = require('fs')
const { Api, JsonRpc, Serialize } = require('eosjs');
const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig');
const fetch = require('node-fetch'); //node only
const { TextDecoder, TextEncoder } = require('util'); //node only
let privateKey1 = '5J***********'
const privateKeys = [privateKey1];
const signatureProvider = new JsSignatureProvider(privateKeys);
const rpc = new JsonRpc('https://jungle2.cryptolions.io:443', { fetch }); //required to read blockchain state
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
const buffer = new Serialize.SerialBuffer({
textEncoder: api.textEncoder,
textDecoder: api.textDecoder,
})
let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
const abiDefinitions = api.abiTypes.get('abi_def')
abiJSON = abiDefinitions.fields.reduce(
(acc, { name: fieldName }) =>
Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
abiJSON
)
abiDefinitions.serialize(buffer, abiJSON)
let serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
deployContract();
async function deployContract(){
try{
const wasmFilePath = './hello.wasm'
const abiFilePath = './hello.abi'
const fs = require('fs')
const { Api, JsonRpc, Serialize } = require('eosjs');
const { JsSignatureProvider } = require('eosjs/dist/eosjs-jssig'); // development only
const fetch = require('node-fetch'); //node only
const { TextDecoder, TextEncoder } = require('util'); //node only
let privateKey1 = '5J***********'
const privateKeys = [privateKey1];
const signatureProvider = new JsSignatureProvider(privateKeys);
const rpc = new JsonRpc('https://jungle2.cryptolions.io:443', { fetch }); //required to read blockchain state
const api = new Api({ rpc, signatureProvider, textDecoder: new TextDecoder(), textEncoder: new TextEncoder() });
const wasmHexString = fs.readFileSync(wasmFilePath).toString('hex')
const buffer = new Serialize.SerialBuffer({
textEncoder: api.textEncoder,
textDecoder: api.textDecoder,
})
let abiJSON = JSON.parse(fs.readFileSync(abiFilePath, 'utf8'))
const abiDefinitions = api.abiTypes.get('abi_def')
abiJSON = abiDefinitions.fields.reduce(
(acc, { name: fieldName }) =>
Object.assign(acc, { [fieldName]: acc[fieldName] || [] }),
abiJSON
)
abiDefinitions.serialize(buffer, abiJSON)
let serializedAbiHexString = Buffer.from(buffer.asUint8Array()).toString('hex')
deployContract();
async function deployContract(){
try{
await api.transact(
{
actions: [
{
account: 'eosio',
name: 'setcode',
authorization: [
{
actor: user_name,
permission: 'active',
},
],
data: {
account: user_name,
vmtype: '0',
vmversion: '0',
code: wasmHexString,
},
},
{
account: 'eosio',
name: 'setabi',
authorization: [
{
actor: user_name,
permission: 'active',
},
],
data: {
account: user_name,
abi: serializedAbiHexString,
},
},
],
},
{
blocksBehind: 3,
expireSeconds: 30,
}
)
}
catch(e){
console.log(e)
}
};
};
Add vmtype and vmversion in data field of setcode.

Using promise in connection string password field returns database not connected

Decrypting password from environment parameter using aws.kms gets not resolved to use in pg-promise connection object. Database can not connect because of empty password. Password gets resolved after about one second from my local machine, long after the koa server is ready. I tried everything to get GraphQL wait for the database connection, but i couldn't find much information to my problem.
When using environment password direct everything works as intended.
My db.init.js
const pgp = require("pg-promise")();
const aws = require("aws-sdk");
const kms = new aws.KMS({
accessKeyId: process.env.ACCESSKEYID,
secretAccessKey: process.env.SECRETACCESSKEY,
region: process.env.REGION
});
let params = {
CiphertextBlob: Buffer.from(
process.env.ENCRYPTED_DATABASE_PASSWORD,
"base64"
)
};
module.exports = kms.decrypt(params, async (err, data) => {
const password = await data.Plaintext.toString("utf-8");
const cn = {
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
password: password,
};
return pgp(cn);
});
Works when changing db.init.js to
(using plain password instead of encrypted password):
const pgp = require("pg-promise")();
const cn = {
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
password: process.env.PLAIN_DATABASE_PASSWORD
};
module.exports = pgp(cn);
Using it in schema:
const { GraphQLSchema, GraphQLObjectType, GraphQLString} = require("graphql");
const db = require("./db.init")
const schema = new GraphQLSchema({
query: new GraphQLObjectType({
name: "RootQueryType",
fields: () => ({
sql: {
type: GraphQLString,
async resolve() {
return await db
.any("SELECT * FROM user;")
.then(data => data[0].name)
.catch(err => `Something went wrong: ${err}`);
}
}
})
})
});
module.exports = schema;
Server file
const Koa = require('koa');
const mount = require('koa-mount');
const graphqlHTTP = require('koa-graphql');
const schema = require('./schemas');
function createServer() {
server.use(
mount(
'/graphql',
graphqlHTTP({
schema,
graphiql: true,
})
)
);
return server;
}
Local Server
const server = require("./server");
const port = 4000;
server().listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}/graphql`);
});
Lambda function
const awsServerlessKoa = require('aws-serverless-koa');
const serverlessMiddleware = require('aws-serverless-koa/middleware');
const server = require('./server');
server().use(serverlessMiddleware());
module.exports.handler = awsServerlessKoa(server);
GraphQL gives failure: "db.any is not a function". In the db object in schema.js is still the unresolved aws kms object in the connection. I didn't try this as a lambda function because i have to make sure that the database is ready when the function fires.
Thanks for the comment vitaly-t, I figured it finally out:
db.init.js
const pgp = require('pg-promise')();
const aws = require('aws-sdk');
const kms = new aws.KMS({
accessKeyId: process.env.ACCESSKEYID,
secretAccessKey: process.env.SECRETACCESSKEY,
region: process.env.REGION,
});
const params = {
CiphertextBlob: Buffer.from(
process.env.DATABASE_PASSWORD,
'base64',
),
};
async function getDb() {
return kms
.decrypt(params)
.promise()
.then(async res => {
const password = await res.Plaintext.toString('utf-8');
return pgp({
host: process.env.DATABASE_HOST,
port: process.env.DATABASE_PORT,
database: process.env.DATABASE_NAME,
user: process.env.DATABASE_USER,
password,
});
});
}
module.exports = getDb();
schema.js
const { importSchema } = require('graphql-import');
const { makeExecutableSchema } = require('graphql-tools');
const dbp = require('../db/init');
const schema = importSchema('src/api/schemas.graphql');
module.exports = dbp.then(db => {
const resolvers = {
Query: {
user: () => {
return db
.any('SELECT * FROM user;')
.then(data => data[0].name);
},
},
};
return makeExecutableSchema({
typeDefs: schema,
resolvers,
});
});
schemas.graphql
type Query {
user: String
}
schema {
query: Query
}
server.js
const Koa = require('koa');
const mount = require('koa-mount');
const graphqlHTTP = require('koa-graphql');
const schema = require('../api/schemas');
function createServer() {
const server = new Koa();
server.use(
mount(
'/graphql',
graphqlHTTP(async () => ({
schema: await schema,
graphiql: true,
})),
),
);
return server;
}
module.exports = createServer;
server.local.js
const server = require('./server');
const port = 4000;
server().listen(port, err => {
if (err) throw err;
console.log(`> Ready on http://localhost:${port}/graphql`);
});
Only the lambda function I didn't test. Should be straight forward.

Resources