This commit is contained in:
QkoSad
2023-08-08 16:02:54 +03:00
commit 0a7a469d56
315 changed files with 426907 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
MONGODB_URI='mongodb+srv://admin:admin@cluster1.ciuxwxd.mongodb.net/libraryApp?retryWrites=true&w=majority'
JWT_SECRET="lsdahlasjkdhalskjdhaslkjdhaslkjhdaslkjdhaskljdha"
+111
View File
@@ -0,0 +1,111 @@
const { ApolloServer } = require('@apollo/server')
const { ApolloServerPluginDrainHttpServer } = require('@apollo/server/plugin/drainHttpServer')
const { expressMiddleware } = require('@apollo/server/express4')
const { makeExecutableSchema } = require('@graphql-tools/schema')
const { WebSocketServer } = require('ws')
const { useServer } = require('graphql-ws/lib/use/ws')
const http = require('http')
const express = require('express')
const cors = require('cors')
const jwt = require('jsonwebtoken')
const mongoose = require('mongoose')
const User = require("./models/user");
const typeDefs = require("./schema");
const resolvers = require("./resolver");
require("dotenv").config();
mongoose.set("strictQuery", false);
const MONGODB_URI = process.env.MONGODB_URI;
console.log("connecting to ", MONGODB_URI);
mongoose
.connect(MONGODB_URI)
.then(() => {
console.log("connect to MongoDB");
})
.catch((err) => {
console.log("error connecting to MONGODG:", err.message);
});
const start = async () => {
const app = express();
const httpServer = http.createServer(app);
const schema = makeExecutableSchema({ typeDefs, resolvers });
const wsServer = new WebSocketServer({
server: httpServer,
paht: "/",
});
const serverCleanup = useServer({ schema }, wsServer);
const server = new ApolloServer({
schema,
plugins: [
ApolloServerPluginDrainHttpServer({ httpServer }),
{
async serverWillStart() {
return {
async drainServer() {
await serverCleanup.dispose();
},
};
},
},
],
});
await server.start();
app.use(
"/",
cors(),
express.json(),
expressMiddleware(server, {
context: async ({ req }) => {
const auth = req ? req.headers.authorization : null;
if (auth && auth.startsWith("Bearer ")) {
const decodedToken = jwt.verify(
auth.substring(7),
process.env.JWT_SECRET
);
const currentUser = await User.findById(decodedToken.id);
return { currentUser };
}
},
})
);
const PORT = 4000;
httpServer.listen(PORT, () =>
console.log(`Server is now running on http://localhost:${PORT}`)
);
};
start();
/*
const server = new ApolloServer({
typeDefs,
resolvers,
});
startStandaloneServer(server, {
listen: { port: 4000 },
context: async ({ req, res }) => {
const auth = req ? req.headers.authorization : null;
if (auth && auth.startsWith("Bearer ")) {
const decodedToken = jwt.verify(
auth.substring(7),
process.env.JWT_SECRET
);
const currentUser = await User.findById(decodedToken.id);
return { currentUser };
}
},
}).then(({ url }) => {
console.log(`Server ready at ${url}`);
});*/
+18
View File
@@ -0,0 +1,18 @@
const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");
const schema = mongoose.Schema({
name: {
type: String,
minlength: 5,
required: true,
unique: true,
},
born: {
type: Number,
},
});
schema.plugin(uniqueValidator);
module.exports = mongoose.model("Author", schema);
+26
View File
@@ -0,0 +1,26 @@
const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");
const schema = mongoose.Schema({
title: {
type: String,
minlength: 5,
required: true,
unique: true,
},
published: {
type: Number,
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: "Author",
},
genres: [
{
type: String,
},
],
});
schema.plugin(uniqueValidator);
module.exports = mongoose.model("Book", schema);
+19
View File
@@ -0,0 +1,19 @@
const mongoose = require("mongoose");
const uniqueValidator = require("mongoose-unique-validator");
const schema = mongoose.Schema({
username: {
type: String,
minlength: 5,
required: true,
unique: true,
},
favoriteGenre: {
type: String,
required: true,
},
});
schema.plugin(uniqueValidator);
module.exports = mongoose.model("User", schema);
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
{
"name": "y",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "nodemon index.js"
},
"author": "",
"license": "ISC",
"dependencies": {
"@apollo/server": "^4.7.4",
"@graphql-tools/schema": "^10.0.0",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
"graphql": "^16.7.0",
"graphql-subscriptions": "^2.0.0",
"graphql-ws": "^5.14.0",
"jsonwebtoken": "^9.0.0",
"mongoose": "^7.3.1",
"mongoose-unique-validator": "^4.0.0",
"uuid": "^9.0.0",
"ws": "^8.13.0"
},
"devDependencies": {
"nodemon": "^2.0.22"
}
}
+102
View File
@@ -0,0 +1,102 @@
const { GraphQLError } = require("graphql");
const { PubSub } = require("graphql-subscriptions");
const Author = require("./models/author");
const Book = require("./models/book");
const User = require("./models/user");
const pubsub = new PubSub();
const resolvers = {
Query: {
authorCount: (root, args) => Author.collection.countDocuments(),
bookCount: (root, args) => Book.collection.countDocuments(),
authors: async (root, args) => {
return await Author.find({});
},
books: async (root, args) => {
try {
if (!args.genre && !args.author)
return await Book.find({}).populate("author");
if (args.author) {
const author = await Author.findOne({ name: args.author });
return await Book.find({ author: author._id }).populate("author");
}
return await Book.find({ genres: args.genre }).populate("author");
} catch (error) {
console.log(error);
throw new GraphQLError("error quering books", {
extensions: {
code: "BAD_USER_INPUT",
},
});
}
},
me: (root, args, context) => context.currentUser,
},
Mutation: {
addBook: async (root, args, context) => {
try {
if (!context.currentUser) throw new GraphQLError("User not authorized");
let author = await Author.findOne({ name: args.author });
if (!author) {
const newAuthor = new Author({ name: args.author });
author = await newAuthor.save();
}
const book = new Book({ ...args, author: author._id });
await book.save();
pubsub.publish("BOOK_ADDED", { bookAdded: book });
return await Book.findOne({ title: book.title }).populate("author");
} catch (err) {
console.log(err);
}
},
addAuthor: async (root, args) => {
const author = new Author({ ...args });
try {
return await author.save();
} catch (err) {
console.log(err);
}
},
editAuthor: async (root, { name, born }, context) => {
if (!context.currentUser) throw new GraphQLError("User not authorized");
const author = await Author.findOne({ name });
author.born = born;
return await author.save();
},
createUser: async (root, args) => {
const user = new User({
username: args.username,
favoriteGenre: args.favoriteGenre,
});
return user.save();
},
login: async (root, { username, password }) => {
const user = await User.findOne({ username });
if (!user || password !== "secret") {
throw new GraphQLError("wrong credentials", {
extensions: {
code: "BAD_USER_INPUT",
},
});
}
const userForToken = {
username: user.username,
id: user._id,
};
return { value: jwt.sign(userForToken, process.env.JWT_SECRET) };
},
},
Author: {
bookCount: async (root) => {
return await Book.count({ author: root._id }).populate("author");
},
},
Subscription: {
bookAdded: {
subscribe: () => pubsub.asyncIterator("BOOK_ADDED"),
},
},
};
module.exports = resolvers;
+50
View File
@@ -0,0 +1,50 @@
const typeDefs = `
type User {
username: String!
favoriteGenre: String!
id: ID!
}
type Token {
value: String!
}
type Author {
name: String!
born: Int
id: ID!
bookCount: Int!
}
type Book {
title: String!
published: Int
id: ID!
author: Author!
genres: [String]
}
type Query {
authorCount: Int!
bookCount: Int!
books(genre:String, author:String): [Book]!
authors: [Author]!
me: User
}
type Mutation {
addBook(
title: String!,
author: String!,
published: Int!,
genres: [String!]!): Book!
editAuthor(born: Int!,name: String!): Author!
addAuthor(name: String!, born: Int): Author!
createUser(username: String! favoriteGenre: String!): User
login(username: String! password: String!): Token
}
type Subscription {
bookAdded: Book!
}
`;
module.exports = typeDefs;