การสร้างสถาปัตยกรรม GraphQL API Codebase ใน Node.js

ตั้งค่าเซิร์ฟเวอร์ GraphQL ด้วยการทำให้เป็นโมดูลและการรับรองความถูกต้อง

แหล่งที่มาของรูปภาพ: ผู้แต่ง

บทช่วยสอนส่วนใหญ่ใน GraphQL ไม่ได้สอนวิธีแยกสคีมาและตัวแก้ไขของคุณ เช่นเดียวกับที่คุณทำให้เส้นทางและตัวควบคุมเป็นโมดูลใน REST API ทั่วไป หรือวิธีกำหนดและโหลดคำจำกัดความประเภทจาก.grapqhlไฟล์แทนที่จะเป็นตัวอักษรเทมเพลต ฉันจะพยายามสอนแนวคิดที่สำคัญเหล่านี้ให้คุณในบทช่วยสอนนี้

ฉันคิดว่าคุณมีความเข้าใจพื้นฐานเกี่ยวกับGraphQLและหลักการทำงานของมัน มิฉะนั้น บทช่วยสอนนี้จะไม่สมเหตุสมผลมากนัก อย่าลังเลที่จะสำรวจที่เก็บโค้ดด้วยตัวคุณเอง และถ้าคุณต้องการเขียนโค้ดร่วมกับฉัน ก็ดีเหมือนกัน

ตั้งค่าเริ่มต้น

เริ่มต้นด้วยเซิร์ฟเวอร์พื้นฐานและติดตั้งการพึ่งพาต่อไปนี้

npm i express express-graphql graphql @graphql-tools/schema

  • express-graphqlเป็นโมดูลที่ให้คุณสร้าง GraphQL API ด้วย Express
  • graphql คือการใช้งานอ้างอิง JavaScript สำหรับ GraphQL
  • @graphql-tools/* เป็นชุดของแพ็คเกจที่ทำให้การทำงานกับ GraphQL ง่ายขึ้น

ข้อมูลในการทำงานด้วย

เราต้องการข้อมูลเพื่อทำงานกับ API ฉันจะใช้ข้อมูลจำลองสำหรับการสาธิต (เก็บไว้ในไฟล์ JS) แต่แนวคิดจะยังคงเหมือนเดิมไม่ว่าคุณจะใช้ข้อมูลจำลองหรือฐานข้อมูล

สร้างไดเร็กทอรีในรูทของ codebase ของคุณที่ตั้งชื่อdataและใส่สิ่งต่อไปนี้:

const authors = [
  { id: 1, name: 'J. K. Rowling' },
  // ... more authors
];
const books = [
  { id: 6, name: 'Forrest Gump', authorId: 2 },
  { id: 7, name: 'The Way of Shadows', authorId: 3 },
  { id: 8, name: 'Beyond the Shadows', authorId: 3 },
  // ... more books
];
exports.authors = authors;
exports.books = books;

กำหนดแบบโมดูลาร์

มาสร้างไดเร็กทอรีใหม่สองไดเร็กทอรีที่รูทของแอปพลิเคชันของเรา:

  • สคีมา (สำหรับการถือคำจำกัดความประเภทสำหรับผู้แต่งและหนังสือ)
  • ตัวแก้ไข (สำหรับฟังก์ชั่นตัวแก้ไขหลุมสำหรับผู้แต่งและหนังสือ)
  • root
     └─ resolvers
         ├─ authors.js
         ├─ authors.js
         └─ index.js
     └─ schemas
         ├─ authors.graphql
         └─ books.graphql
         └─ index.graphql
     ├─ package.json
     └─ server.js
    

    // index.graphql
    type Query {
      _empty: String
      # define any root queries here
    }
    type Mutation {
      _empty: String
      # define any root queries here
    }
    

// authors.graphql
type Author {
  id: Int!
  name: String!
  books: [Book]
}
# extending root query type we defined in index.grapqhl
extend type Query {
  authors: [Author]
  author(id: Int!): Author!
}

// books.graphql
type Book {
  id: Int!
  title: String!
  authorId: Int!
  author: Author!
}
extend type Query {
  books: [Book]!
  book(id: Int!): Book!
}
input NewBook {
  title: String!
  authorId: Int!
}
extend type Mutation {
  createBook(newBook: NewBook): Book!
}

หากคุณกำลังใช้ VSCode และคุณไม่เห็นการเน้นไวยากรณ์ / อัตโนมัติเสร็จในของคุณ.graphqlไฟล์ติดตั้งอย่างเป็นทางการ GraphQL Extention

กำหนดตัวแก้ไข

ตอนนี้เราได้กำหนดสคีมาสำหรับหนังสือและผู้แต่งแล้ว ถึงเวลาสร้างตัวแก้ไขสำหรับผู้แต่งและหนังสือ

// resolvers/authors.js
const { authors, books } = require('../data');
const authorsResolvers = {
  Query: {
    authors: () => authors,
    author: (parent, { id }) => {
      return authors.find((author) => author.id === id);
    }
  },
  Author: {
    books: (author) => {
      return books.filter((book) => book.authorId === author.id);
    }
  }
};
module.exports = authorsResolvers;

// resolvers/books.js
const { authors, books } = require('../data');
const booksResolvers = {
  Query: {
    books: () => books,
    book: (parent, { id }) => {
      return books.find((book) => book.id === id);
    }
  },
  Book: {
    author: (book) => {
      return authors.find((author) => author.id === book.authorId);
    }
  },
  Mutation: {
    createBook: (parent, { newBook }) => {
      const createdBook = { id: books.length + 1, ...newBook };
      books.push(createdBook);
      return createdBook;
    }
  }
};
module.exports = booksResolvers;

// resolvers/index.js
const authorsResolvers = require('./authors');
const booksResolvers = require('./books');
const rootResolver = {};
const resolvers = [
  rootResolver,
  authorsResolvers,
  booksResolvers,
];
module.exports = resolvers;

  • การนำเข้าตัวแก้ไขทั้งหมด (หนังสือและผู้แต่งในกรณีนี้)
  • การกำหนดตัวแก้ไขรูท
  • การส่งออกอาร์เรย์ของตัวแก้ไข (graphql-tools จะจัดการรวมโดยอัตโนมัติ)

สุดท้าย เราสามารถนำเข้าสคีมาและตัวแก้ไขในserver.js. เนื่องจากฉันใช้.graphqlไฟล์สำหรับการกำหนดประเภท ฉันจะใช้เครื่องมือ graphql ขนาดเล็กสองตัวที่ช่วยฉันอ่าน.graphqlไฟล์

npm i @graphql-tools/load @graphql-tools/graphql-file-loader

ฉันกำลังใช้รูปแบบ glob สำหรับการโหลดคำจำกัดความประเภท ดังนั้นloadSchemaSyncจะโหลด.graphqlไฟล์ทั้งหมดจากschemasไดเร็กทอรีและจะรวมเข้าด้วยกันเพื่อสร้างสคีมาเดียว

ตอนนี้ เรามีเซิร์ฟเวอร์ GraphQL ที่ทำงานอยู่ที่localhost:5000/graphqlและเราสามารถดำเนินการค้นหาต่อไปนี้:

การสาธิต

การตรวจสอบสิทธิ์

การเพิ่มการรับรองความถูกต้องให้กับ GraphQL API นั้นง่ายมาก เพียงเพิ่มมิดเดิลแวร์ด่วนก่อนกำหนด/graphqlเส้นทางในserver.js

จากนั้นในฟังก์ชันรีโซลเวอร์ของคุณ คุณสามารถทำ

// resolvers/authors.js
const authorsResolvers = {
  Query: {
    authors: (parent, args, context) => {
      if (!context.isAuthenticated) {
        throw new Error('You are not authenticated');
      }
return authors;
    },
    author: (parent, { id }) => {
      return authors.find((author) => author.id === id);
    }
  },
};

เนื่องจากเราจำเป็นต้องดำเนินการตรวจสอบสิทธิ์ในทุกตัวแก้ไข ดังนั้นแทนที่จะตรวจสอบว่าผู้ใช้ได้รับการตรวจสอบสิทธิ์ในทุกตัวแก้ไขเดียวหรือไม่ เราสามารถใช้เครื่องมือ@graphql-toolsที่ช่วยให้เรากำหนดมิดเดิลแวร์การพิสูจน์ตัวตนเพียงครั้งเดียวสำหรับชุดข้อความค้นหาหรือการกลายพันธุ์

npm i @graphql-tools/resolvers-composition

// resolvers/authors.js
const { composeResolvers } =
  require('@graphql-tools/resolvers-composition');
const { authors, books } = require('../data');
const authorsResolvers = {
  Query: {
    authors: (parent, args, context) => {
      return authors;
    },
    author: (parent, { id }) => {
      return authors.find((author) => author.id === id);
    }
  },
};
const authenticateReq = (next) => {
  return (root, args, context, info) => {
    if (!context.isAuthenticated) {
      throw new Error('You are not authorized');
    }
    return next(root, args, context, info);
  };
};
// run auth middleware for all types and all fields
// on authors resolver
module.exports = composeResolvers(authorsResolvers, {
  '*.*': [authenticateReq],
});

คุณสามารถปฏิบัติตามแนวทางเดียวกันสำหรับทรัพยากรหนังสือของ API ของเรา ดูการสนับสนุนรูปแบบ glob สำหรับองค์ประกอบ resolvers ที่นี่

นี่คือจุดเริ่มต้นของโปรเจ็กต์ GraphQL ที่ซับซ้อน แต่วิธีการจัดโครงสร้างจะช่วยให้คุณดูแลโค้ดของคุณได้อย่างง่ายดายเนื่องจากทรัพยากรเป็นแบบโมดูลาร์

ขอบคุณที่อ่าน. นี่คือพื้นที่เก็บข้อมูลรหัส

Suggested posts

การค้นหาข้อมูลเกี่ยวกับชื่อโดเมน

ตัดตอนมาจาก Small, Sharp Software Tools โดย Brian P. Hogan

การค้นหาข้อมูลเกี่ยวกับชื่อโดเมน

เมื่อคุณส่งคำขอไปที่ facebook.com คอมพิวเตอร์ของคุณจะค้นหาชื่อโดเมนเพื่อแปลชื่อโดเมนนั้นเป็นที่อยู่ IP เพื่อให้คอมพิวเตอร์ของคุณสามารถเชื่อมต่อได้

การปฏิวัติแบบไม่ใช้โค้ด: ปลดปล่อยความรุ่งเรืองทางธุรกิจด้วย Webflow, Framer, Bubble.io,

การปฏิวัติแบบไม่ใช้โค้ด: ปลดปล่อยความรุ่งเรืองทางธุรกิจด้วย Webflow, Framer, Bubble.io,

เริ่มต้นการเดินทางอันน่าตื่นเต้นของนวัตกรรมและความสำเร็จในขณะที่คุณเข้าถึงศักยภาพที่ยังไม่ได้ใช้ของแพลตฟอร์มที่ไม่ต้องเขียนโค้ดที่น่าประหลาดใจเหล่านี้ ให้ฉันแบ่งปันเรื่องราวกับคุณเกี่ยวกับ Sapna นักธุรกิจหญิงที่โดดเด่น

Related posts

ชีวิตไร้ขีดจำกัด

เมื่อคุณโตขึ้น คุณมักจะได้รับการบอกว่าโลกเป็นอย่างที่มันเป็น และชีวิตของคุณก็แค่ใช้ชีวิตอยู่ในโลก ไม่เสี่ยงชีวิต แค่เดินตามเส้นทางที่กำหนดและตายในที่สุด และพยายามอย่า ทุบกำแพงมากเกินไป แต่นั่นเป็นชีวิตที่จำกัดมาก

การสร้างสภาพแวดล้อมการทำงานที่ปลอดภัย

การสร้างสภาพแวดล้อมการทำงานที่ปลอดภัย

“เขาจะปกป้องฉันเมื่อฉันตกอยู่ในอันตราย เขาจะซ่อนฉันไว้ในเต็นท์ของเขา

การรวบรวม OSINT เพื่อการล่าภัยคุกคาม

การรวบรวม OSINT เพื่อการล่าภัยคุกคาม

สวัสดีชาวไซเบอร์! ยินดีต้อนรับกลับสู่ OSINT สำหรับซีรี่ส์การล่าภัยคุกคาม ในบทความแรก ฉันได้ให้ภาพรวมของ OSINT และความสำคัญในการตามล่าภัยคุกคาม

บทสนทนาอันตราย

บทสนทนาอันตราย

หากเราต้องการจะเติบโตบนโลกใบนี้ต่อไป เราจะต้องสนทนาที่อันตราย คนที่ท้าทายสิ่งที่เราทำ สิ่งที่เรากำลังทำ และสิ่งที่เรากำลังจะทำต่อไป (หรือกำลังวางแผนที่จะทำ)