Bạn có thể đã nghe các nhà phát triển ca ngợi những điều kỳ diệu của GraphQL. Trong loạt bài này, chúng tôi muốn tìm hiểu các công nghệ bằng cách sử dụng chúng và bài viết này sẽ giới thiệu cho các bạn một ứng dụng mẫu sử dụng GraphQL.
GraphQL là gì
GraphQL là một ngôn ngữ truy vấn và thời gian chạy có thể được sử dụng để xây dựng các API. Nó giữ một vị trí tương tự trong ngăn xếp phát triển như một API REST nhưng linh hoạt hơn. Không giống như REST, GraphQL cho phép máy khách chỉ định các định dạng và nội dung phản hồi. Cũng giống như SQL SELECT
câu lệnh cho phép xác định kết quả truy vấn, GraphQL cho phép chỉ định cấu trúc dữ liệu JSON trả về. Theo phép tương tự SQL, GraphQL không cung cấp WHERE
nhưng xác định các trường trên các đối tượng ứng dụng sẽ cung cấp dữ liệu cho phản hồi.
GraphQL, như tên cho thấy, mô hình hóa các API như thể ứng dụng là một biểu đồ dữ liệu. Mặc dù mô tả này có thể không phải là cách bạn xem ứng dụng của mình, nhưng nó là một mô hình được sử dụng trong hầu hết các hệ thống. Dữ liệu có thể được biểu diễn bởi JSON là một biểu đồ vì JSON chỉ là một biểu đồ có hướng. Nghĩ về ứng dụng như trình bày một mô hình đồ thị thông qua API sẽ làm cho GraphQL dễ hiểu hơn nhiều.
Sử dụng GraphQL trong một ứng dụng
Bây giờ chúng ta đã mô tả GraphQL trong phần tóm tắt, chúng ta hãy bắt đầu thực sự xây dựng một ứng dụng sử dụng GraphQL bằng cách bắt đầu với định nghĩa về mô hình dữ liệu hoặc biểu đồ. Năm ngoái, tôi có một thú vui mới. Tôi đang học cách chơi âm bass thẳng đứng cũng như tìm hiểu về âm nhạc nói chung, vì vậy tôi nghĩ đến một ví dụ liên quan đến âm nhạc khi tạo ra một ứng dụng demo.
Các loại đối tượng trong ví dụ là Nghệ sĩ và Bài hát . Nghệ sĩ có nhiều Bài hát và một Bài hát được liên kết với Nghệ sĩ . Mỗi loại đối tượng có các thuộc tính như name
.
Xác định API
GraphQL sử dụng SDL (Ngôn ngữ định nghĩa lược đồ) đôi khi được gọi là "ngôn ngữ định nghĩa hệ thống kiểu" trong đặc tả GraphQL. Về lý thuyết, các loại GraphQL có thể được định nghĩa bằng bất kỳ ngôn ngữ nào nhưng ngôn ngữ bất khả tri phổ biến nhất là SDL, vì vậy hãy sử dụng SDL để định nghĩa API.
type Artist {
name: String!
songs: [Song]
origin: [String]
}
type Song {
name: String!
artist: Artist
duration: Int
release: String
}
Một Nghệ sĩ có name
đó là String
. Dấu chấm than có nghĩa là trường non-null
. songs
là một mảng của Bài hát đối tượng và origin
là một String
mảng. Bài hát tương tự nhưng với một trường lẻ. release
trường phải là loại thời gian hoặc ngày nhưng GraphQL không có loại đó được xác định là loại cốt lõi. Để có tính di động hoàn chỉnh giữa các triển khai GraphQL khác nhau, một String
Được sử dụng. Việc triển khai GraphQL mà chúng tôi sẽ sử dụng có Time
đã thêm nhập, vì vậy hãy thay đổi Bài hát định nghĩa để release
trường là Time
loại hình. Giá trị trả về sẽ là String
, nhưng bằng cách đặt loại thành Time
chúng tôi ghi lại API chính xác hơn.
release: Time
Bước cuối cùng là mô tả cách lấy một hoặc nhiều đối tượng. Điều này được gọi là gốc hoặc, đối với các truy vấn, là gốc truy vấn. Thư mục gốc của chúng tôi sẽ chỉ có một trường hoặc một phương thức được gọi là artist
và sẽ yêu cầu một name
nghệ sĩ .
type Query {
artist(name: String!): Artist
}
Viết đơn
Hãy xem cách chúng ta sẽ sử dụng điều này trong một ứng dụng. Có một số cách triển khai máy chủ GraphQL cho Ruby. Một số cách tiếp cận yêu cầu SDL ở trên phải được dịch sang một ngôn ngữ tương đương Ruby. Agoo, một máy chủ HTTP mà tôi đã xây dựng, sử dụng định nghĩa SDL như nó vốn có và mã Ruby là Ruby vani đơn giản, vì vậy đó là những gì chúng tôi sẽ sử dụng.
Lưu ý rằng các lớp Ruby phù hợp với các kiểu GraphQL. Bằng cách đặt tên lớp Ruby khớp với tên loại GraphQL, chúng tôi không thêm bất kỳ sự phức tạp nào không cần thiết.
class Artist
attr_reader :name
attr_reader :songs
attr_reader :origin
def initialize(name, origin)
@name = name
@songs = []
@origin = origin
end
# Only used by the Song to add itself to the artist.
def add_song(song)
@songs << song
end
end
class Song
attr_reader :name # string
attr_reader :artist # reference
attr_reader :duration # integer
attr_reader :release # time
def initialize(name, artist, duration, release)
@name = name
@artist = artist
@duration = duration
@release = release
artist.add_song(self)
end
end
Các phương thức khớp với các trường trong các lớp Ruby. Lưu ý rằng các phương thức không có đối số hoặc args={}
. Đây là những gì API GraphQL mong đợi và việc triển khai của chúng tôi ở đây cũng phù hợp. initialize
được sử dụng để thiết lập dữ liệu cho ví dụ, như chúng ta sẽ thấy ngay sau đây.
Lớp gốc truy vấn cũng cần được xác định. Lưu ý artist
phương thức phù hợp với SDL Query
loại gốc. attr_reader
cho các nghệ sĩ artists
cũng đã được thêm vào. Điều đó sẽ được hiển thị với API chỉ bằng cách thêm trường đó vào Query
nhập vào tài liệu SDL.
class Query
attr_reader :artists
def initialize(artists)
@artists = artists
end
def artist(args={})
@artists[args['name']]
end
end
Gốc GraphQL (không nên nhầm lẫn với gốc truy vấn) nằm phía trên gốc truy vấn. GraphQL định nghĩa nó có ba trường tùy chọn. Trong trường hợp này, lớp Ruby thực hiện trên query
đồng ruộng. Trình khởi tạo tải lên một số dữ liệu cho một ban nhạc Indie từ New Zealand mà tôi muốn nghe.
class Schema
attr_reader :query
attr_reader :mutation
attr_reader :subscription
def initialize()
# Set up some data for testing.
artist = Artist.new('Fazerdaze', ['Morningside', 'Auckland', 'New Zealand'])
Song.new('Jennifer', artist, 240, Time.utc(2017, 5, 5))
Song.new('Lucky Girl', artist, 170, Time.utc(2017, 5, 5))
Song.new('Friends', artist, 194, Time.utc(2017, 5, 5))
Song.new('Reel', artist, 193, Time.utc(2015, 11, 2))
@artists = {artist.name => artist}
@query = Query.new(@artists)
end
end
Thiết lập cuối cùng là thực hiện cụ thể. Tại đây, máy chủ được khởi tạo để bao gồm một trình xử lý cho /graphql
Đường dẫn yêu cầu HTTP và sau đó nó được bắt đầu.
Agoo::Server.init(6464, 'root', thread_count: 1, graphql: '/graphql')
Agoo::Server.start()
Sau đó, việc triển khai GraphQL được định cấu hình với SDL được xác định trước đó ($songs_sdl
) và sau đó ứng dụng sẽ ngủ trong khi máy chủ xử lý các yêu cầu.
Agoo::GraphQL.schema(Schema.new) {
Agoo::GraphQL.load($songs_sdl)
}
sleep
Mã cho ví dụ này có thể được tìm thấy trên GitHub.
Sử dụng API
Để kiểm tra API, bạn có thể sử dụng trình duyệt web, Postman hoặc curl
.
Truy vấn GraphQL để thử có dạng như sau:
{
artist(name:"Fazerdaze") {
name
songs{
name
duration
}
}
}
Truy vấn yêu cầu Nghệ sĩ được đặt tên là Fazerdaze
và trả về name
và songs
trong tài liệu JSON. Đối với mỗi Bài hát tên artists
và duration
của Bài hát được trả về trong một đối tượng JSON. Đầu ra sẽ giống như thế này.
{
"data": {
"artist": {
"name": "Fazerdaze",
"songs": [
{
"name": "Jennifer",
"duration": 240
},
{
"name": "Lucky Girl",
"duration": 170
},
{
"name": "Friends",
"duration": 194
},
{
"name": "Reel",
"duration": 193
}
]
}
}
}
Sau khi loại bỏ khoảng trắng tùy chọn trong truy vấn, HTTP GET được tạo bằng curl sẽ trả về nội dung đó.
curl -w "\n" 'localhost:6464/graphql?query=\{artist(name:"Fazerdaze")\{name,songs\{name,duration\}\}\}&indent=2'
Hãy thử thay đổi truy vấn và thay thế duration
với release
và lưu ý việc chuyển đổi Ruby Time thành chuỗi JSON.
Chuyển sang bài hát
Chúng tôi rất thích chơi với GraphQL và chúng tôi hy vọng bạn đã gắn thẻ và học được điều gì đó trên đường đi. Cảm ơn bạn, bạn đã là một khán giả tuyệt vời. Nếu bạn muốn nói thêm về Ruby, chúng ta sẽ đến quầy bán hàng.