Started with Mongo

This commit is contained in:
Riccardo
2021-01-02 13:11:59 +01:00
parent 5294122f61
commit 30407cac0a
41 changed files with 33775 additions and 0 deletions

7
server/.gitignore vendored Normal file
View File

@@ -0,0 +1,7 @@
.env*
dist
package-lock.json
node_modules
.idea
.vscode
*.log

3
server/README.md Normal file
View File

@@ -0,0 +1,3 @@
# hackernews-graphql-js
This repository contains the final project for the [**GraphQL.js tutorial**](https://www.howtographql.com/graphql-js/0-introduction/) on [How to GraphQL](https://www.howtographql.com/). Note that it also serves as foundation for all frontend tutorials on the site.

30
server/package.json Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "server",
"version": "1.0.0",
"license": "MIT",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"dependencies": {
"apollo-server": "^2.19.0",
"apollo-server-express": "^2.19.1",
"bcryptjs": "2.4.3",
"body-parser": "^1.19.0",
"chai": "^4.2.0",
"cors": "^2.8.5",
"express": "^4.17.1",
"express-graphql": "^0.12.0",
"graphql": "^14.7.0",
"graphql-tools": "^7.0.2",
"jsonwebtoken": "8.5.1",
"migrate": "^1.7.0",
"mocha": "^8.2.1",
"mongodb": "^3.6.3",
"mongoose": "^5.11.9",
"node-migrate": "^0.1.0"
},
"devDependencies": {
"nodemon": "^2.0.6"
}
}

99
server/src/index.js Normal file
View File

@@ -0,0 +1,99 @@
const { ApolloServer, PubSub } = require('apollo-server');
var MongoClient = require('mongodb', { useUnifiedTopology: true }).MongoClient;
// import { MongoClient } from 'mongodb'
const Query = require('./resolvers/Query');
const Mutation = require('./resolvers/Mutation');
const Subscription = require('./resolvers/Subscription');
const User = require('./resolvers/User');
const Appointment = require('./resolvers/Appointment');
const Follow = require('./resolvers/Follow');
const fs = require('fs');
const path = require('path');
const { getUserId } = require('./utils');
const pubsub = new PubSub();
// const mongo = new MongoClient({
// errorFormat: 'minimal'
// });
const mongo = MongoClient.connect("mongodb+srv://admin:hEbAjhvkrFDHAP3@cluster0.0hjtt.mongodb.net/Calendar?retryWrites=true&w=majority", function (err, db) {
if (err) throw err;
console.log("ALL good");
//Write databse Insert/Update/Query code here..
});
const resolvers = {
Query,
Mutation,
Subscription,
User,
Appointment,
Follow
};
let db;
const server = new ApolloServer({
typeDefs: fs.readFileSync(
path.join(__dirname, 'schema.graphql'),
'utf8'
),
resolvers,
// context: async () => {
// if (!db) {
// try {
// const dbClient = new MongoClient(
// 'mongodb+srv://test:qwerty123@cluster0-yvwjx.mongodb.net/next-graphql?retryWrites=true&w=majority',
// {
// useNewUrlParser: true,
// useUnifiedTopology: true,
// }
// )
// if (!dbClient.isConnected()) await dbClient.connect()
// db = dbClient.db('next-graphql') // database name
// } catch (e) {
// console.log('--->error while connecting with graphql context (db)', e)
// }
// }
// return { db }
// },
context: ({ req }) => {
return {
...req,
mongo,
pubsub,
userId:
req && req.headers.authorization
? getUserId(req)
: null
};
},
subscriptions: {
onConnect: (connectionParams) => {
if (connectionParams.authToken) {
return {
mongo,
userId: getUserId(
null,
connectionParams.authToken
)
};
} else {
return {
mongo
};
}
}
}
});
server
.listen()
.then(({ url }) =>
console.log(`Server is running on ${url}`)
);

View File

@@ -0,0 +1,16 @@
function createdBy(parent, args, context) {
return context.mongo.appointment
.findUnique({ where: { id: parent.id } })
.createdBy();
}
function follows(parent, args, context) {
return context.mongo.appointment
.findUnique({ where: { id: parent.id } })
.follows();
}
module.exports = {
createdBy,
follows
};

View File

@@ -0,0 +1,16 @@
function appointment(parent, args, context) {
return context.mongo.follow
.findUnique({ where: { id: parent.id } })
.appointment();
}
function user(parent, args, context) {
return context.mongo.follow
.findUnique({ where: { id: parent.id } })
.user();
}
module.exports = {
appointment,
user
};

View File

@@ -0,0 +1,91 @@
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const { APP_SECRET } = require('../utils');
function createAppointment(parent, args, context, info) {
const { userId } = context;
const newAppointment = context.mongo.appointment.create({
data: {
title: args.title,
description: args.description,
createdBy: { connect: { id: userId } }
}
});
return newAppointment;
}
async function signup(parent, args, context, info) {
console.log(context);
const password = await bcrypt.hash(args.password, 10);
const user = await context.mongo.user.create({
data: { ...args, password }
});
const token = jwt.sign({ userId: user.id }, APP_SECRET);
return {
token,
user
};
}
async function login(parent, args, context, info) {
const user = await context.mongo.user.findUnique({
where: { email: args.email }
});
if (!user) {
throw new Error('No such user found');
}
const valid = await bcrypt.compare(
args.password,
user.password
);
if (!valid) {
throw new Error('Invalid password');
}
const token = jwt.sign({ userId: user.id }, APP_SECRET);
return {
token,
user
};
}
async function follow(parent, args, context, info) {
const { userId } = context;
const follow = await context.mongo.follow.findUnique({
where: {
linkId_userId: {
linkId: Number(args.linkId),
userId: userId
}
}
});
if (Boolean(follow)) {
throw new Error(
`Already followed the appointment: ${args.linkId}`
);
}
const newFollow = context.mongo.follow.create({
data: {
user: { connect: { id: userId } },
link: { connect: { id: Number(args.linkId) } }
}
});
context.pubsub.publish('NEW_FOLLOW', newFollow);
return newFollow;
}
module.exports = {
createAppointment,
signup,
login,
follow
};

View File

@@ -0,0 +1,30 @@
async function feed(parent, args, context, info) {
console.log(context);
const where = args.filter
? {
OR: [
{ title: { contains: args.filter } },
{ description: { contains: args.filter } }
]
}
: {};
const appointments = await context.mongo.appointment.findMany({
where,
skip: args.skip,
take: args.take,
orderBy: args.orderBy
});
const count = await context.mongo.appointment.count({ where });
return {
id: 'main-feed',
appointments,
count
};
}
module.exports = {
feed
};

View File

@@ -0,0 +1,26 @@
function newLinkSubscribe(parent, args, context, info) {
return context.pubsub.asyncIterator("NEW_LINK")
}
const newAppointment = {
subscribe: newLinkSubscribe,
resolve: payload => {
return payload
},
}
function newFollowSubscribe(parent, args, context, info) {
return context.pubsub.asyncIterator("NEW_FOLLOW")
}
const newFollow = {
subscribe: newFollowSubscribe,
resolve: payload => {
return payload
},
}
module.exports = {
newAppointment,
newFollow
}

View File

@@ -0,0 +1,9 @@
function appointments(parent, args, context) {
return context.mongo.user
.findUnique({ where: { id: parent.id } })
.appointments();
}
module.exports = {
appointments
};

78
server/src/schema.graphql Normal file
View File

@@ -0,0 +1,78 @@
type Query {
info: String!
feed(
filter: String
skip: Int
take: Int
orderBy: AppointmentOrderByInput
): Feed!
}
type Feed {
id: ID!
appointments: [Appointment!]!
count: Int!
}
type Mutation {
createAppointment(
title: String!,
description: String!,
start: DateTime!,
end: DateTime!,
): Appointment!
signup(
email: String!
password: String!
name: String!
): AuthPayload
login(email: String!, password: String!): AuthPayload
follow(appointmentId: ID!): Follow
}
type Subscription {
newAppointment: Appointment
newFollow: Follow
}
type AuthPayload {
token: String
user: User
}
type User {
id: ID!
name: String!
email: String!
appointments: [Appointment!]!
}
type Appointment {
id: ID!
title: String!
description: String!
start: DateTime!
end: DateTime!
createdBy: User
follows: [Follow!]!
createdAt: DateTime!
}
type Follow {
id: ID!
appointment: Appointment!
user: User!
}
input AppointmentOrderByInput {
description: Sort
url: Sort
createdAt: Sort
}
enum Sort {
asc
desc
}
scalar DateTime

30
server/src/utils.js Normal file
View File

@@ -0,0 +1,30 @@
const jwt = require('jsonwebtoken');
const APP_SECRET = 'GraphQL-is-aw3some';
function getTokenPayload(token) {
return jwt.verify(token, APP_SECRET);
}
function getUserId(req, authToken) {
if (req) {
const authHeader = req.headers.authorization;
if (authHeader) {
const token = authHeader.replace('Bearer ', '');
if (!token) {
throw new Error('No token found');
}
const { userId } = getTokenPayload(token);
return userId;
}
} else if (authToken) {
const { userId } = getTokenPayload(authToken);
return userId;
}
throw new Error('Not authenticated');
}
module.exports = {
APP_SECRET,
getUserId
};

4472
server/yarn.lock Normal file

File diff suppressed because it is too large Load Diff