Điểm của kiểu đầu vào trong GraphQL là gì?


83

Bạn có thể vui lòng giải thích tại sao nếu đối số đầu vào của đột biến là đối tượng thì nó phải là kiểu đầu vào ? Tôi nghĩ đơn giản hơn nhiều chỉ cần sử dụng lại loại mà không cần cung cấp id.

Ví dụ:

type Sample {
  id: String
  name: String
}

input SampleInput {
  name: String
}

type RootMutation {
  addSample(sample: Sample): Sample  # <-- instead of it should be
  addSample(sample: SampleInput): Sample
}

Đối với đối tượng nhỏ thì không sao, nhưng khi bạn có nhiều đối tượng có hơn 10 thuộc tính trong lược đồ, điều đó sẽ trở thành gánh nặng.


30
Các đối tượng đầu vào phải có thể tuần tự hóa. Bởi vì các đối tượng đầu ra có thể chứa các chu trình, chúng không thể được sử dụng lại cho đầu vào.
Jesse Buchanan

1
Jesse, có vẻ như là đủ câu trả lời! Bạn có thể trả lời và tôi đánh dấu nó như vậy.
Dmitry Dushkin

Tự hỏi liệu có thể kết hợp các giao diện với nó không
MVCDS

Câu trả lời:


99

Từ thông số kỹ thuật:

Kiểu Đối tượng GraphQL (ObjectTypeDefinition) ... không thích hợp để sử dụng lại [làm đầu vào], vì kiểu Đối tượng có thể chứa các trường xác định đối số hoặc chứa tham chiếu đến giao diện và kết hợp, không loại nào thích hợp để sử dụng làm đối số đầu vào . Vì lý do này, các đối tượng đầu vào có một kiểu riêng biệt trong hệ thống.

Đó là "lý do chính thức", nhưng có một số lý do thực tế khiến bạn không thể sử dụng kiểu đối tượng làm kiểu đối tượng đầu vào hoặc sử dụng kiểu đối tượng làm kiểu đối tượng đầu vào:

Chức năng

Các kiểu đối tượng và kiểu đối tượng đầu vào đều có các trường, tuy nhiên các trường đó có các thuộc tính khác nhau phản ánh cách các kiểu này được lược đồ sử dụng. Lược đồ của bạn sẽ có khả năng xác định các đối số và một số loại hàm phân giải cho các trường của loại đối tượng, nhưng các thuộc tính này không có ý nghĩa trong ngữ cảnh đầu vào (tức là bạn không thể phân giải trường của đối tượng đầu vào - nó đã có một giá trị rõ ràng) . Tương tự, các giá trị mặc định chỉ có thể được cung cấp cho các trường kiểu đối tượng đầu vào chứ không phải các trường kiểu đối tượng.

Nói cách khác, điều này có vẻ giống như sự trùng lặp:

type Student {
  name: String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade
}

Nhưng việc thêm các tính năng cụ thể cho một trong hai kiểu đối tượng hoặc kiểu đối tượng đầu vào làm rõ ràng rằng chúng hoạt động khác nhau:

type Student {
  name(preferred: Boolean): String
  grade: Grade
}

input StudentInput {
  name: String
  grade: Grade = F
}

Loại giới hạn hệ thống

Các loại trong GraphQL được nhóm thành các loại đầu raloại đầu vào .

Loại đầu ra là loại có thể được trả về như một phần của phản hồi do dịch vụ GraphQL tạo ra. Kiểu đầu vào là kiểu đầu vào hợp lệ cho các đối số trường hoặc chỉ thị.

Có sự chồng chéo giữa hai nhóm này (tức là vô hướng, enum, danh sách và không null). Tuy nhiên, các kiểu trừu tượng như liên hiệp và giao diện không có ý nghĩa trong bối cảnh đầu vào và không thể được sử dụng làm đầu vào. Việc tách biệt các kiểu đối tượng và kiểu đối tượng đầu vào cho phép bạn đảm bảo rằng một kiểu trừu tượng không bao giờ được sử dụng khi kiểu đầu vào được mong đợi.

Thiết kế lược đồ

Khi đại diện cho một thực thể trong lược đồ của bạn, có khả năng một số thực thể sẽ thực sự "chia sẻ trường" giữa các loại đầu vào và đầu ra tương ứng của chúng:

type Student {
  firstName: String
  lastName: String
  grade: Grade
}

input StudentInput {
  firstName: String
  lastName: String
  grade: Grade
}

Tuy nhiên, các kiểu đối tượng có thể (và trong thực tế thường xuyên làm) mô hình hóa các cấu trúc dữ liệu rất phức tạp:

type Student {
  fullName: String!
  classes: [Class!]!
  address: Address!
  emergencyContact: Contact
  # etc
}

Mặc dù các cấu trúc này có thể chuyển thành các đầu vào thích hợp (chúng tôi tạo Sinh viên, vì vậy chúng tôi cũng truyền vào một đối tượng đại diện cho địa chỉ của chúng), nhưng chúng thường không - tức là có thể chúng tôi cần chỉ định các lớp của học sinh theo ID lớp và ID phần, không phải vật. Tương tự, chúng ta có thể có các trường muốn trả về nhưng không muốn thay đổi hoặc ngược lại (như một passwordtrường).

Hơn nữa, ngay cả đối với các thực thể tương đối đơn giản, chúng ta thường có các yêu cầu khác nhau xung quanh tính nullability giữa các kiểu đối tượng và các đối tượng đầu vào "đối tác" của chúng. Thông thường, chúng tôi muốn đảm bảo rằng một trường cũng sẽ được trả về trong một phản hồi, nhưng chúng tôi không muốn tạo các trường tương tự được yêu cầu trong đầu vào của mình. Ví dụ,

type Student {
  firstName: String!
  lastName: String!
}

input StudentInput {
  firstName: String
  lastName: String
}

Cuối cùng, trong nhiều lược đồ, thường không có ánh xạ 1-1 giữa loại đối tượng và loại đối tượng đầu vào cho một thực thể nhất định. Một mẫu phổ biến là sử dụng các loại đối tượng đầu vào riêng biệt cho các hoạt động khác nhau để tinh chỉnh hơn nữa xác thực đầu vào cấp giản đồ:

input CreateUserInput {
  firstName: String!
  lastName: String!
  email: String!
  password: String!
}

input UpdateUserInput {
  email: String
  password: String
}

Tất cả các ví dụ này minh họa một điểm quan trọng - trong khi một loại đối tượng đầu vào đôi khi có thể phản chiếu một loại đối tượng, bạn ít có khả năng thấy điều đó trong các lược đồ sản xuất do yêu cầu kinh doanh.


4
đây thực sự là một câu trả lời tuyệt vời!
Charlie Ng

Hãy sửa cho tôi nếu tôi sai nhưng trong ví dụ của bạn, kiểu Gradekhông thể được sử dụng lại trong đầu vào StudentInput, phải không? Bạn sẽ cần các trường nội tuyến trong đối tượng đầu vào hoặc có một GradeInputđối tượng đầu vào.
Matt

2
@Matt Câu hỏi hay! Trong ví dụ trên, Gradelà một kiểu enum. Không giống như các đối tượng, các kiểu vô hướng (như String, Int, v.v.) và kiểu enums có thể được sử dụng làm cả kiểu đầu vào kiểu đầu ra.
Daniel Rearden

lời giải thích hay
Visakh Vijayan

Câu trả lời thực sự tuyệt vời!
Johnny

25

Nhận xét của Jesse là đúng. Để có câu trả lời chính thức hơn, đây là đoạn trích từ tài liệu GraphQL về các loại đầu vào :

Kiểu Đối tượng được xác định ở trên không thích hợp để sử dụng lại ở đây, vì Đối tượng có thể chứa các trường thể hiện các tham chiếu vòng tròn hoặc tham chiếu đến các giao diện và kết hợp, cả hai đều không thích hợp để sử dụng làm đối số đầu vào. Vì lý do này, các đối tượng đầu vào có một kiểu riêng biệt trong hệ thống.

CẬP NHẬT

Kể từ khi đăng nó, tôi thấy rằng các tham chiếu vòng tròn thực sự có thể chấp nhận được, miễn là những tham chiếu đó là nilable (hoặc nếu không nó sẽ khai báo một chuỗi vô hạn). Tuy nhiên, vẫn còn những hạn chế khác (ví dụ: giao diện) dường như yêu cầu một hệ thống loại riêng biệt cho các đầu vào.


4
Ở đây có thêm một số thảo luận về lý do tồn tại hạn chế này: github.com/graphql/graphql-js/issues/599
Cam Jackson
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.