TOOGLE
GraphQL basic - Back-End
.node_modules
- src/
  - index.js
  - server/
    - schemas/
      - bookSchema.js
      - authorSchema.js
      - publisherSchema.js
    - models/
      - bookModel.js
      - authorModel.js
      - publisherModel.js
    - resolvers/
      - resolvers.js
      - bookResolver.js
      - authorResolver.js
      - publisherResolver.js

  - graphql/
    - typedefs.js

  - db/
    - index.js
.env
.gitignore
.package-lock.json
.package.json

---------------------------------------------------------------------
-db/index.js

import mongoose from 'mongoose';
import 'dotenv/config';

export const connectToDatabase = async () => {
  try {
    await mongoose.connect(process.env.SECRET_URL, {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    });
    console.log('Connected to database');
  } catch (error) {
    console.error('Error connecting to database:', error.message);
  }
};

export default connectToDatabase;

---------------------------------------------------------------------

- bookSchema.js

import { Schema } from 'mongoose';

const bookSchema = new Schema({
    title: String,
    publisher: {
      type: Schema.Types.ObjectId,
      ref: 'Publisher',
    },
    author: [{
      type: Schema.Types.ObjectId,
      ref: 'Author',
    }],
  });

  export default bookSchema;

---------------------------------------------------------------------

- bookModel.js

import { model } from 'mongoose';
import bookSchema from '../schemas/bookSchema.js';

const Book = model('Book', bookSchema, 'my_books_collection');

export default Book;

---------------------------------------------------------------------

- bookResolver.js

import Book from '../models/bookModel.js';
import Author from '../models/authorModel.js';
import Publisher from '../models/publisherModel.js';

const bookResolver = {
  Query: {
    books: async (_, { limit, order }) => {
      try {
       let books;
       if(order === 'ASC'){
          if(limit){
              books = await Book.find().sort({ title: 1 }).limit(limit);
          }else {
              books = await Book.find().sort({ title: 1 });
          }
       }else if (order === 'DESC'){
          if(limit){
              books = await Book.find().sort({ title: -1 }).limit(limit);
          }else {
              books = await Book.find().sort({ title: -1 });
          }
       } else {
          if(limit){
              books = Book.find().limit(limit);
          }else {
              books = Book.find();
          }
       }
       return books;
      } catch (error) {
        throw new Error(`Failed to fetch books: ${error.message}`);
      }
    },
  },
  Book: {
    author: async (parent) => {
      const authors = await Author.find({ _id: { $in: parent.author } });
      return authors;
    },
    publisher: async (parent) => {
      if (parent.publisher) {
        const publisher = await Publisher.findById(parent.publisher);
        return publisher;
      }
      return null;
    },
  },
};

export default bookResolver;

---------------------------------------------------------------------
- resolvers.js

import authorResolver from './authorResolver.js'; 
import bookResolver from './bookResolver.js';
import publisherResolver from './publisherResolver.js';
import photoResolver from './photoResolver.js';

const resolvers = {
    Query: {
      ...authorResolver.Query,
      ...bookResolver.Query,
      ...publisherResolver.Query,
      ...photoResolver.Query,
    },
    Author: {
      ...authorResolver.Author,
    },
    Book: {
      ...bookResolver.Book,
    },
    Publisher: {
      ...publisherResolver.Publisher,
    },
  };

  export default resolvers;

---------------------------------------------------------------------

- typedefs.js

export const typeDefs = `
  type Book {
    title: String
    author: [Author]
    publisher: Publisher
  }

  type Author {
    name: String
    booksByAuthor: [Book]
  }

  type Publisher {
    company: String
    booksByPublisher: [Book]
  }

  type Query {
    books(limit: Int, order: String): [Book]
    authors(limit: Int): [Author]
    publishers(filter: String): [Publisher]
    photos(limit: Int): [Photos]
  }

  type Photos {
    imageUrl: String
  }

`;

export default typeDefs;

---------------------------------------------------------------------
index.js

import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
import typeDefs from './graphql/typedefs.js';
import resolvers from './server/resolvers/resolvers.js';
import connectToDatabase from './db/index.js';


const startServer = async () => {
  try {
    await connectToDatabase();

    const server = new ApolloServer({
      typeDefs,
      resolvers,
      introspection: true,
    });

    const { url } = await startStandaloneServer(server, {
      listen: { port: 4000 },
    });

    console.log(`🚀  Server ready at: ${url}`);

  } catch (error) {
    console.error('Error starting server:', error.message);
  }
};

startServer();

------