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
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);
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());
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;
}
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.
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.