Refactor database setup and add user context to GQL requests (#17)

* Add context to each request

* Implement get user db query

* Move constants to a separate file

* Refactor database init method
This commit is contained in:
neerajvijay1997 2024-01-17 10:53:01 +05:30 committed by Ashwin Phatak
parent 4d00cfb8f0
commit e4c099f8c3
7 changed files with 63 additions and 28 deletions

View File

@ -2,3 +2,6 @@
host = "127.0.0.1"
port = 8000
gqlPath = "/graphql"
[database]
dbPath = "db/snowball"

View File

@ -4,6 +4,11 @@ export interface ServerConfig {
gqlPath?: string;
}
export interface DatabaseConfig {
dbPath: string;
}
export interface Config {
server: ServerConfig;
database: DatabaseConfig;
}

View File

@ -0,0 +1,4 @@
export const DEFAULT_GQL_PATH = '/graphql';
// Note: temporary hardcoded user, later to be derived from auth token
export const USER_ID = 1;

View File

@ -2,23 +2,35 @@ import { DataSource } from 'typeorm';
import path from 'path';
import debug from 'debug';
const log = debug('snowball:server');
import { User } from './entity/User';
import { DatabaseConfig } from './config';
export const initializeDatabase = async (
database: string = 'db/snowball'
): Promise<void> => {
try {
const AppDataSource = new DataSource({
const log = debug('snowball:database');
export class Database {
private dataSource: DataSource;
constructor ({ dbPath }: DatabaseConfig) {
this.dataSource = new DataSource({
type: 'better-sqlite3',
database,
database: dbPath,
entities: [path.join(__dirname, '/entity/*')],
synchronize: true,
logging: false
});
await AppDataSource.initialize();
log('database initialized');
} catch (error) {
log(error);
}
};
async init () : Promise<void> {
await this.dataSource.initialize();
log('database initialized');
}
async getUser (userId: number) : Promise<User | null> {
const userRepository = this.dataSource.getRepository(User);
const user = await userRepository.findOneBy({
id: userId
});
return user;
}
}

View File

@ -3,22 +3,26 @@ import debug from 'debug';
import fs from 'fs';
import path from 'path';
import { initializeDatabase } from './database';
import { Database } from './database';
import { createAndStartServer } from './server';
import { createResolvers } from './resolvers';
import { getConfig } from './utils';
import { Config } from './type';
import { Config } from './config';
const log = debug('snowball:server');
const configFilePath = 'environments/local.toml';
export const main = async (): Promise<void> => {
// TODO: get config path using cli
const { server } = await getConfig<Config>(configFilePath);
const { server, database } = await getConfig<Config>(configFilePath);
const db = new Database(database);
await db.init();
await initializeDatabase();
const typeDefs = fs.readFileSync(path.join(__dirname, 'schema.gql')).toString();
await createAndStartServer(typeDefs, createResolvers, server);
const resolvers = await createResolvers(db);
await createAndStartServer(typeDefs, resolvers, server);
};
main()

View File

@ -1,12 +1,16 @@
const user = {
id: 2
};
import { Database } from './database';
export const createResolvers = async (): Promise<any> => {
export const createResolvers = async (db: Database): Promise<any> => {
return {
Query: {
// TODO: fetch user data from db
user: () => user
user: (
_: any,
__: any,
// TODO: add custom type for context
context: any
) => {
return db.getUser(context.userId);
}
}
};
};

View File

@ -10,12 +10,11 @@ import {
import { TypeSource } from '@graphql-tools/utils';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { ServerConfig } from './type';
import { ServerConfig } from './config';
import { DEFAULT_GQL_PATH, USER_ID } from './constants';
const log = debug('snowball:server');
const DEFAULT_GQL_PATH = '/graphql';
export const createAndStartServer = async (
typeDefs: TypeSource,
resolvers: any,
@ -31,12 +30,16 @@ export const createAndStartServer = async (
// Create the schema
const schema = makeExecutableSchema({
typeDefs,
resolvers: await resolvers()
resolvers
});
const server = new ApolloServer({
schema,
csrfPrevention: true,
context: () => {
// TODO: Use userId derived from auth token
return { userId: USER_ID };
},
plugins: [
// Proper shutdown for the HTTP server
ApolloServerPluginDrainHttpServer({ httpServer }),