Nối tiếp Phần một về Schema Definition Language của GraphQL, bài viết này trình bày tiếp các khái niệm được sử dụng để định nghĩa GraphQL Schema
1. Interfaces
- Cũng giống như khái niệm Interface ở các language khác, trong GraphQL, một Interface là một asbstract type có thể bao gồm một tập nhất định các field mà các type khi implement nó cũng phải bao gồm các field đó.
- Ví dụ, bạn có một interface
Character
đại diện cho bất kì nhân vật nào trong Star Wars1234567<span class="token keyword">interface</span> <span class="token class-name">Character</span> <span class="token punctuation">{</span><span class="token attr-name">id</span><span class="token punctuation">:</span> ID<span class="token operator">!</span><span class="token attr-name">name</span><span class="token punctuation">:</span> String<span class="token operator">!</span><span class="token attr-name">friends</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Character<span class="token punctuation">]</span><span class="token attr-name">appearsIn</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Episode<span class="token punctuation">]</span><span class="token operator">!</span><span class="token punctuation">}</span>
Bất kì type nào mà ImplementsCharacters
cần phải có đầy đủ các trường trên với cùng tham số hay cùng type. - Ví dụ, các type sáu đây có thể implement
Character
1234567891011121314151617<span class="token keyword">type</span> <span class="token class-name">Human</span> <span class="token keyword">implements</span> <span class="token class-name">Character</span> <span class="token punctuation">{</span><span class="token attr-name">id</span><span class="token punctuation">:</span> ID<span class="token operator">!</span><span class="token attr-name">name</span><span class="token punctuation">:</span> String<span class="token operator">!</span><span class="token attr-name">friends</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Character<span class="token punctuation">]</span><span class="token attr-name">appearsIn</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Episode<span class="token punctuation">]</span><span class="token operator">!</span><span class="token attr-name">starships</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Starship<span class="token punctuation">]</span><span class="token attr-name">totalCredits</span><span class="token punctuation">:</span> Int<span class="token punctuation">}</span><span class="token keyword">type</span> <span class="token class-name">Droid</span> <span class="token keyword">implements</span> <span class="token class-name">Character</span> <span class="token punctuation">{</span><span class="token attr-name">id</span><span class="token punctuation">:</span> ID<span class="token operator">!</span><span class="token attr-name">name</span><span class="token punctuation">:</span> String<span class="token operator">!</span><span class="token attr-name">friends</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Character<span class="token punctuation">]</span><span class="token attr-name">appearsIn</span><span class="token punctuation">:</span> <span class="token punctuation">[</span>Episode<span class="token punctuation">]</span><span class="token operator">!</span><span class="token attr-name">primaryFunction</span><span class="token punctuation">:</span> String<span class="token punctuation">}</span>
Cả 3 type này đều có tất cả các trường từCharacter
interface, đồng thời cũng có các trường bổ sung nhưtotalCredits
,starships
,primaryFunction
giúp xác định các loại Character cụ thể. - Interface hữu ích khi mà bạn muốn trả về một object hay là một bộ các object, nhưng chúng lại có các trường khác nhau.
- Ví dụ, câu query sau sẽ sinh ra lỗi
QUERY DEFINITION
1234type Query {hero(episode: Episode): Character}
CLIENT CALL QUERY123456789<span class="token keyword">query</span> HeroForEpisode<span class="token punctuation">(</span><span class="token variable">$ep</span><span class="token punctuation">:</span> Episode<span class="token operator">!</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>hero<span class="token punctuation">(</span><span class="token attr-name">episode</span><span class="token punctuation">:</span> <span class="token variable">$ep</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>name<span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Droid</span> <span class="token punctuation">{</span>primaryFunction<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
VARIABLES1234<span class="token punctuation">{</span><span class="token property">"ep"</span><span class="token operator">:</span> <span class="token string">"JEDI"</span><span class="token punctuation">}</span>
RESULT1234567891011121314<span class="token punctuation">{</span><span class="token property">"errors"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token property">"message"</span><span class="token operator">:</span> <span class="token string">"Cannot query field "primaryFunction" on type "Character". Did you mean to use an inline fragment on "Droid"?"</span><span class="token punctuation">,</span><span class="token property">"locations"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token property">"line"</span><span class="token operator">:</span> <span class="token number">4</span><span class="token punctuation">,</span><span class="token property">"column"</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">}</span> - Trường
hero
trả về một kiểuCharacter
, nó có thể làHuman
hayDroid
tùy thuộc vào biếnepisode
. Trong câu query trên bạn chỉ có thể chỉ định trả về những field mà tồn tại trongCharacter
interface, như vậy sẽ không cóprimaryFunction
- Để yêu cầu trả về các trường trong một object type cụ thể, sử dụng inline fragments
2. Union types
- Ví dụ12<span class="token keyword">union</span> <span class="token class-name">SearchResult</span> <span class="token operator">=</span> Human <span class="token operator">|</span> Droid <span class="token operator">|</span> Starship
- Bất cứ khi nào chúng ta trả về một loại
Search Result
trong schema, SearchResult này có thể là mộtHuman
,Droid
, hoặc mộtStarship
. Các thành phần của một union type cần phải là một loại đối tượng cụ thể, không được là một interface hay là một union khác - Khi phía client query một field mà trả về một union type là
SearchResult
, chúng ta cần phải sử dụng inline fragment để có thể query bất kì trường nào.CLIENT QERRY
123456789101112131415161718<span class="token punctuation">{</span>search<span class="token punctuation">(</span><span class="token attr-name">text</span><span class="token punctuation">:</span> <span class="token string">"an"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>__typename<span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Human</span> <span class="token punctuation">{</span>nameheight<span class="token punctuation">}</span><span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Droid</span> <span class="token punctuation">{</span>nameprimaryFunction<span class="token punctuation">}</span><span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Starship</span> <span class="token punctuation">{</span>namelength<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
RESULT12345678910111213141516171819202122<span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token property">"search"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span><span class="token property">"__typename"</span><span class="token operator">:</span> <span class="token string">"Human"</span><span class="token punctuation">,</span><span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Han Solo"</span><span class="token punctuation">,</span><span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">1.8</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token property">"__typename"</span><span class="token operator">:</span> <span class="token string">"Human"</span><span class="token punctuation">,</span><span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"Leia Organa"</span><span class="token punctuation">,</span><span class="token property">"height"</span><span class="token operator">:</span> <span class="token number">1.5</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">{</span><span class="token property">"__typename"</span><span class="token operator">:</span> <span class="token string">"Starship"</span><span class="token punctuation">,</span><span class="token property">"name"</span><span class="token operator">:</span> <span class="token string">"TIE Advanced x1"</span><span class="token punctuation">,</span><span class="token property">"length"</span><span class="token operator">:</span> <span class="token number">9.2</span><span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">}</span><span class="token punctuation">}</span> - Trường __typename là một String giúp bạn phân biệt sự khác nhau giữa các object type ở Client
- Ở ví dụ này, vì
Human
vàDroid
cùng implement một interface chung làCharacter
nên bạn có thể query những trường chung của 2 object type này ở chỉ một chỗ mà không cần lặp lại các trường giống nhau ở mỗi type, ví dụ sau đây cho kết quả như bên trên:12345678910111213141516171819<span class="token punctuation">{</span>search<span class="token punctuation">(</span><span class="token attr-name">text</span><span class="token punctuation">:</span> <span class="token string">"an"</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>__typename<span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Character</span> <span class="token punctuation">{</span>name<span class="token punctuation">}</span><span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Human</span> <span class="token punctuation">{</span>height<span class="token punctuation">}</span><span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Droid</span> <span class="token punctuation">{</span>primaryFunction<span class="token punctuation">}</span><span class="token operator">...</span> <span class="token keyword">on</span> <span class="token class-name">Starship</span> <span class="token punctuation">{</span>namelength<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
Lưu ý: Trườngname
vẫn phải được chỉ định đối với Starship bởiStarship
không phải là mộtCharacter
3.Input types
- Từ đầu đến giờ, chúng ta chỉ nói về truyền vào một field các argument thuộc về kiểu scalar như enums hay strings. Tuy nhiên bạn có thể truyền argument là một object phức tạp. Điều này cực kì hữu ích khi bạn muốn truyền vào toàn bộ object để tạo cái gì đó.
- Trong GraphQL SDL, input types nhìn sẽ giống một object types thông tường nhưng với keyword input thay vì type12345<span class="token keyword">input</span> ReviewInput <span class="token punctuation">{</span><span class="token attr-name">stars</span><span class="token punctuation">:</span> Int<span class="token operator">!</span><span class="token attr-name">commentary</span><span class="token punctuation">:</span> String<span class="token punctuation">}</span>
- Ví dụ sử dụng input type trong một mutation
MUTATION DEFINITION
1234567<span class="token keyword">mutation</span> CreateReviewForEpisode<span class="token punctuation">(</span><span class="token variable">$ep</span><span class="token punctuation">:</span> Episode<span class="token operator">!</span><span class="token punctuation">,</span> <span class="token variable">$review</span><span class="token punctuation">:</span> ReviewInput<span class="token operator">!</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>createReview<span class="token punctuation">(</span><span class="token attr-name">episode</span><span class="token punctuation">:</span> <span class="token variable">$ep</span><span class="token punctuation">,</span> <span class="token attr-name">review</span><span class="token punctuation">:</span> <span class="token variable">$review</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>starscommentary<span class="token punctuation">}</span><span class="token punctuation">}</span>
VARIABLES12345678<span class="token punctuation">{</span><span class="token property">"ep"</span><span class="token operator">:</span> <span class="token string">"JEDI"</span><span class="token punctuation">,</span><span class="token property">"review"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token property">"stars"</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"commentary"</span><span class="token operator">:</span> <span class="token string">"This is a great movie!"</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
RESULT123456789<span class="token punctuation">{</span><span class="token property">"data"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token property">"createReview"</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token property">"stars"</span><span class="token operator">:</span> <span class="token number">5</span><span class="token punctuation">,</span><span class="token property">"commentary"</span><span class="token operator">:</span> <span class="token string">"This is a great movie!"</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
4. Kết luận
- Quan hai phần của chủ đề này, mình đã trình bày các khái niệm được sử dụng trong Schema Difinition Language. Mình tin là những khái niệm này đủ để bạn có thể tự định nghĩa một schema cơ bản của mình. Mong bài viết có ích đối với các bạn
- Nguồn tham khảo