আপনি শুনে থাকতে পারেন ডেভেলপাররা GraphQL-এর আশ্চর্য গান গাচ্ছেন। এই সিরিজে আমরা টেকনোলজি শিখি সেগুলো ব্যবহার করে, এবং এই আর্টিকেল একটি উদাহরণ অ্যাপ্লিকেশনের মাধ্যমে যাবে যা GraphQL ব্যবহার করে।
GraphQL কী
GraphQL একটি কোয়েরি ল্যাঙ্গুয়েজ এবং রানটাইম যা API বানাতে ব্যবহার করা যেতে পারে। এটি ডেভেলপমেন্ট স্ট্যাকে REST API-এর সমান অবস্থান ধারণ করে কিন্তু আরও ফ্লেক্সিবিলিটির সাথে। REST-এর বিপরীতে, GraphQL রেসপন্স ফরম্যাট এবং কন্টেন্ট ক্লায়েন্ট দ্বারা স্পেসিফাই করার অনুমতি দেয়। ঠিক যেমন SQL SELECT স্টেটমেন্ট কোয়েরি রেজাল্ট স্পেসিফাই করতে দেয়, GraphQL রিটার্ন হওয়া JSON ডেটা স্ট্রাকচার স্পেসিফাই করতে দেয়। SQL সাদৃশ্য অনুসরণ করলে, GraphQL WHERE ক্লজ প্রদান করে না কিন্তু অ্যাপ্লিকেশন অবজেক্টের ফিল্ড আইডেন্টিফাই করে যেগুলো রেসপন্সের জন্য ডেটা প্রদান করবে।
GraphQL, নামটিই ইঙ্গিত দেয়, APIs-কে মডেল করে যেন অ্যাপ্লিকেশন একটি ডেটা গ্রাফ। যদিও এই বর্ণনা হতে পারে আপনি আপনার অ্যাপ্লিকেশন কীভাবে দেখেন সেটা না হোক, এটি অধিকাংশ সিস্টেমে ব্যবহৃত একটি মডেল। JSON দ্বারা রিপ্রেজেন্ট করা ডেটা একটি গ্রাফ যেহেতু JSON শুধু একটি ডায়रेक्टেড গ্রাফ। অ্যাপ্লিকেশনকে গ্রাফ মডেল презেন্ট করার মাধ্যমে API হিসেবে ভাবলে GraphQL অনেক সহজ বোঝা যাবে।
একটি অ্যাপ্লিকেশনে GraphQL ব্যবহার
এখন যেহেতু আমরা GraphQL কী তা অ্যাবস্ট্রাক্টলি বর্ণনা করেছি, আসুন একদম অ্যাপ্লিকেশন বানাতে শুরু করি GraphQL ব্যবহার করে ডেটা মডেল বা গ্রাফের ডেফিনিশন দিয়ে। গত বছর আমি একটি নতুন হবি শুরু করলাম। আমি ইলেকট্রিক আপ্রাইট বাস বাজানো শিখছি এবং μουσিক সম্পর্কে জানছি, তাই একটি মিউজিক-রিলেটেড উদাহরণ মনে आया ডেমো অ্যাপের জন্য।
উদাহরণের অবজেক্ট টাইপগুলো হলো Artist এবং Song। Artists-এর একাধিক Song থাকে এবং একটি Song একটি Artist-এর সাথে অ্যাসোসিয়েটেড। প্রতিটি অবজেক্ট টাইপের অ্যাট্রিবিউট আছে যেমন name।
API ডিফাইন করা
GraphQL SDL (Schema Definition Language) ব্যবহার করে যেটি কখনো কখনো "type system definition language" বলা হয় GraphQL স্পেসিফিকেশনে। GraphQL টাইপগুলো থিওরেটিক্যালি যেকোনো ল্যাঙ্গুয়েজে ডিফাইন করা যেতে পারে কিন্তু সবচেয়ে সাধারণ অগনস্টিক ল্যাঙ্গুয়েজ হলো SDL তাই আমরা SDL ব্যবহার করব API ডিফাইন করতে।
type Artist { name: String! songs: [Song] origin: [String] } type Song { name: String! artist: Artist duration: Int release: String }
একজন Artist-এর একটি name আছে যেটি একটি String। এক্সক্লামেশন মার্ক মানে ফিল্ডটি non-null। songs হলো Song অবজেক্টের একটি অ্যারে, এবং origin যেটি একটি String অ্যারে। Song সিমিলার কিন্তু একটি অদ্ভুত ফিল্ডের সাথে। release ফিল্ডটি একটি টাইম বা ডেট টাইপ হওয়া উচিত কিন্তু GraphQL সেটি কোর টাইপ হিসেবে ডিফাইন করে নেই। পূর্ণ পোর্টেবিলিটি različные GraphQL ইমপ্লিমেন্টেশনের মধ্যে, একটি String ব্যবহার করা হয়। আমরা যে GraphQL ইমপ্লিমেন্টেশন ব্যবহার করব সেটিতে Time টাইপ যোগ করা আছে তাই আসুন Song ডেফিনিশন পরিবর্তন করি যাতে release ফিল্ডটি Time টাইপ হয়। রিটার্নড ভ্যালু হবে একটি String, কিন্তু টাইপ Time সেট করে আমরা API-কে আরও সঠিকভাবে ডকুমেন্ট করছি।
release: Time
শেষ ধাপ হলো বর্ণনা করা কীভাবে এক বা একাধিক অবজেক্ট পেতে হয়। এটাকে রুট বলা হয় বা, কোয়েরির জন্য, কোয়েরি রুট। আমাদের রুটে শুধু একটি ফিল্ড বা মেথড থাকবে artist নামে এবং এটি একটি আর্টিস্ট name রিকোয়ার করবে।
type Query { artist(name: String!): Artist }
অ্যাপ্লিকেশন লিখা
আসুন দেখি কীভাবে আমরা এটি একটি অ্যাপ্লিকেশনে ব্যবহার করব। রুবির জন্য GraphQL সার্ভারের একাধিক ইমপ্লিমেন্টেশন আছে। কিছু অ্যাপ্রোচ SDL-কে উপরে রুবি ইকুিভ্যালেন্টে ট্রান্সলেট করতে বাধ্য করে। Agoo, একটি HTTP সার্ভার যা আমি বানিয়েছি, SDL ডেফিনিশন ব্যবহার করে যেনটা আছে এবং রুবি কোড প্লেন ভ্যানিলা রুবি, তাই আমরা সেটি ব্যবহার করব।
নোট করুন যে রুবি ক্লাসগুলো GraphQL টাইপের সাথে ম্যাচ করে। রুবি ক্লাসের নাম GraphQL টাইপের নামের সাথে মিলিয়ে, আমরা কোনো অপ্রয়োজনীয় জটিলতা যোগ করছি না।
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
মেথডগুলো রুবি ক্লাসে ফিল্ডের সাথে ম্যাচ করে। নোট করুন যে মেথডগুলোর আর্গুমেন্ট হয় না বা args={}। এটি GraphQL API-র এক্সপেক্টেশন এবং আমাদের ইমপ্লিমেন্টেশন এখানে সেটি ফলো করে। initialize মেথডগুলো উদাহরণের জন্য ডেটা সেট আপ করতে ব্যবহৃত হয়, যেন আমরা শীঘ্রই দেখব।
কোয়েরি রুট ক্লাসও ডিফাইন করতে হবে। নোট করুন artist মেথডটি যেটি SDL Query রুট টাইপের সাথে ম্যাচ করে। artists এর জন্য একটি attr_reader ও যোগ করা হয়েছে। সেটি API-এ এক্সপোজ হবে শুধু SDL ডকুমেন্টে Query টাইপে সেটি ফিল্ড হিসেবে যোগ করলে।
class Query attr_reader :artists def initialize(artists) @artists = artists end def artist(args={}) @artists[args['name']] end end
GraphQL রুট (কোয়েরি রুটের সাথে বিভ্রান্ত হবেন না) কোয়েরি রুটের উপরে থাকে। GraphQL এটি অপশনালি তিনটি ফিল্ড দিয়ে ডিফাইন করে। রুবি ক্লাসটি, এই কেসে, query ফিল্ড ইমপ্লিমেন্ট করে। ইনিশিয়ালাইজার কিছু ডেটা লোড করে टेস্টিং জন্য একটি ইন্ডি ব্যান্ডের জন্য নিউজিল্যান্ড থেকে যেটি আমি শুনতে পছন্দ করি।
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
ফাইনাল সেটআপ ইমপ্লিমেন্টেশন-স্পেসিফিক। এখানে, সার্ভারটি ইনিশিয়ালাইজ করা হয় /graphql HTTP রিকোয়েস্ট পাথের জন্য একটি হ্যান্ডলার ইনক্লুড করে এবং তারপর এটি Стар্ট করা হয়।
Agoo::Server.init(6464, 'root', thread_count: 1, graphql: '/graphql') Agoo::Server.start()
GraphQL ইমপ্লিমেন্টেশন তখন কনফিগার করা হয় আগে ডিফাইন করা SDL-এ ($songs_sdl) এবং তারপর অ্যাপ্লিকেশন স্লিপ করে যতক্ষণ না সার্ভার রিকোয়েস্ট প্রসেস করে।
Agoo::GraphQL.schema(Schema.new) { Agoo::GraphQL.load($songs_sdl) } sleep
এই উদাহরণের কোড GitHub-এ পাওয়া যাবে।
API ব্যবহার করা
API টেস্ট করতে, আপনি ওয়েব ব্রাউজার, Postman বা curl ব্যবহার করতে পারেন।
GraphQL কোয়েরি যা ট্রাই করতে পারেন সেটি এভাব আপনি শুনে থাকতে পারেন ডেভেলপাররা GraphQL-এর আশ্চর্য গান গাচ্ছেন। এই সিরিজে আমরা টেকনোলজি শিখি সেগুলো ব্যবহার করে, এবং এই আর্টিকেল একটি উদাহরণ অ্যাপ্লিকেশনের মাধ্যমে যাবে যা GraphQL ব্যবহার করে। GraphQL একটি কোয়েরি ল্যাঙ্গুয়েজ এবং রানটাইম যা API বানাতে ব্যবহার করা যেতে পারে। এটি ডেভেলপমেন্ট স্ট্যাকে REST API-এর সমান অবস্থান ধারণ করে কিন্তু আরও ফ্লেক্সিবিলিটির সাথে। REST-এর বিপরীতে, GraphQL রেসপন্স ফরম্যাট এবং কন্টেন্ট ক্লায়েন্ট দ্বারা স্পেসিফাই করার অনুমতি দেয়। ঠিক যেমন SQL GraphQL, নামটিই ইঙ্গিত দেয়, APIs-কে মডেল করে যেন অ্যাপ্লিকেশন একটি ডেটা গ্রাফ। যদিও এই বর্ণনা হতে পারে আপনি আপনার অ্যাপ্লিকেশন কীভাবে দেখেন সেটা না হোক, এটি অধিকাংশ সিস্টেমে ব্যবহৃত একটি মডেল। JSON দ্বারা রিপ্রেজেন্ট করা ডেটা একটি গ্রাফ যেহেতু JSON শুধু একটি ডায়रेक्टেড গ্রাফ। অ্যাপ্লিকেশনকে গ্রাফ মডেল презেন্ট করার মাধ্যমে API হিসেবে ভাবলে GraphQL অনেক সহজ বোঝা যাবে। এখন যেহেতু আমরা GraphQL কী তা অ্যাবস্ট্রাক্টলি বর্ণনা করেছি, আসুন একদম অ্যাপ্লিকেশন বানাতে শুরু করি GraphQL ব্যবহার করে ডেটা মডেল বা গ্রাফের ডেফিনিশন দিয়ে। গত বছর আমি একটি নতুন হবি শুরু করলাম। আমি ইলেকট্রিক আপ্রাইট বাস বাজানো শিখছি এবং موسیিক সম্পর্কে জানছি, তাই একটি মিউজিক-রিলেটেড উদাহরণ মনে आया ডেমো অ্যাপের জন্য। উদাহরণের অবজেক্ট টাইপগুলো হলো Artist এবং Song। Artists-এর একাধিক Song থাকে এবং একটি Song একটি Artist-এর সাথে অ্যাসোসিয়েটেড। প্রতিটি অবজেক্ট টাইপের অ্যাট্রিবিউট আছে যেমন GraphQL SDL (Schema Definition Language) ব্যবহার করে যেটি কখনো কখনো "type system definition language" বলা হয় GraphQL স্পেসিফিকেশনে। GraphQL টাইপগুলো থিওরেটিক্যালি যেকোনো ল্যাঙ্গুয়েজে ডিফাইন করা যেতে পারে কিন্তু সবচেয়ে সাধারণ অগনস্টিক ল্যাঙ্গুয়েজ হলো SDL তাই আমরা SDL ব্যবহার করব API ডিফাইন করতে। একজন Artist-এর একটি শেষ ধাপ হলো বর্ণনা করা কীভাবে এক বা একাধিক অবজেক্ট পেতে হয়। এটাকে রুট বলা হয় বা, কোয়েরির জন্য, কোয়েরি রুট। আমাদের রুটে শুধু একটি ফিল্ড বা মেথড থাকবে আসুন দেখি কীভাবে আমরা এটি একটি অ্যাপ্লিকেশনে ব্যবহার করব। রুবির জন্য GraphQL সার্ভারের একাধিক ইমপ্লিমেন্টেশন আছে। কিছু অ্যাপ্রোচ SDL-কে উপরে রুবি ইকুিভ্যালেন্টে ট্রান্সলেট করতে বাধ্য করে। Agoo, একটি HTTP সার্ভার যা আমি বানিয়েছি, SDL ডেফিনিশন ব্যবহার করে যেনটা আছে এবং রুবি কোড প্লেন ভ্যানিলা রুবি, তাই আমরা সেটি ব্যবহার করব। নোট করুন যে রুবি ক্লাসগুলো GraphQL টাইপের সাথে ম্যাচ করে। রুবি ক্লাসের নাম GraphQL টাইপের নামের সাথে মিলিয়ে, আমরা কোনো অপ্রয়োজনীয় জটিলতা যোগ করছি না। মেথডগুলো রুবি ক্লাসে ফিল্ডের সাথে ম্যাচ করে। নোট করুন যে মেথডগুলোর আর্গুমেন্ট হয় না বা কোয়েরি রুট ক্লাসও ডিফাইন করতে হবে। নোট করুন GraphQL রুট (কোয়েরি রুটের সাথে বিভ্রান্ত হবেন না) কোয়েরি রুটের উপরে থাকে। GraphQL এটি অপশনালি তিনটি ফিল্ড দিয়ে ডিফাইন করে। রুবি ক্লাসটি, এই কেসে, ফাইনাল সেটআপ ইমপ্লিমেন্টেশন-স্পেসিফিক। এখানে, সার্ভারটি ইনিশিয়ালাইজ করা হয় GraphQL ইমপ্লিমেন্টেশন তখন কনফিগার করা হয় আগে ডিফাইন করা SDL-এ ( এই উদাহরণের কোড GitHub-এ পাওয়া যাবে। API টেস্ট করতে, আপনি ওয়েব ব্রাউজার, Postman বা GraphQL কোয়েরি যা ট্রাই করতে পারেন সেটি এই طرح: কোয়েরিটি Artist নামক অপশনাল হোয়াইটস্পেস কোয়েরি থেকে বাদ দেওয়ার পর, একটি HTTP GET কোয়েরি পরিবর্তন করে আমরা GraphQL নিয়ে খেলতে উপভোগ করেছি এবং আশা করি আপনি সাথে সাথে থাকলেন এবং পথে কিছু শিখলেন। ধন্যবাদ, আপনি একটি চমৎকার দর্শক। আপনি যদি আরও রুবি নিয়ে কথা বলতে চান, আমরা বারে মার্চ bánতে থাকব।GraphQL কী
SELECT স্টেটমেন্ট কোয়েরি রেজাল্ট স্পেসিফাই করতে দেয়, GraphQL রিটার্ন হওয়া JSON ডেটা স্ট্রাকচার স্পেসিফাই করতে দেয়। SQL সাদৃশ্য অনুসরণ করলে, GraphQL WHERE ক্লজ প্রদান করে না কিন্তু অ্যাপ্লিকেশন অবজেক্টের ফিল্ড আইডেন্টিফাই করে যেগুলো রেসপন্সের জন্য ডেটা প্রদান করবে।একটি অ্যাপ্লিকেশনে GraphQL ব্যবহার
name।API ডিফাইন করা
type Artist { name: String! songs: [Song] origin: [String] } type Song { name: String! artist: Artist duration: Int release: String } name আছে যেটি একটি String। এক্সক্লামেশন মার্ক মানে ফিল্ডটি non-null। songs হলো Song অবজেক্টের একটি অ্যারে, এবং origin যেটি একটি String অ্যারে। Song সিমিলার কিন্তু একটি অদ্ভুত ফিল্ডের সাথে। release ফিল্ডটি একটি টাইম বা ডেট টাইপ হওয়া উচিত কিন্তু GraphQL সেটি কোর টাইপ হিসেবে ডিফাইন করে নেই। পূর্ণ পোর্টেবিলিটি różnych GraphQL ইমপ্লিমেন্টেশনের মধ্যে, একটি String ব্যবহার করা হয়। আমরা যে GraphQL ইমপ্লিমেন্টেশন ব্যবহার করব সেটিতে Time টাইপ যোগ করা আছে তাই আসুন Song ডেফিনিশন পরিবর্তন করি যাতে release ফিল্ডটি Time টাইপ হয়। রিটার্নড ভ্যালু হবে একটি String, কিন্তু টাইপ Time সেট করে আমরা API-কে আরও সঠিকভাবে ডকুমেন্ট করছি। release: Time artist নামে এবং এটি একটি আর্টিস্ট name রিকোয়ার করবে।type Query { artist(name: String!): Artist } অ্যাপ্লিকেশন লিখা
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 endargs={}। এটি GraphQL API-র এক্সপেক্টেশন এবং আমাদের ইমপ্লিমেন্টেশন এখানে সেটি ফলো করে। initialize মেথডগুলো উদাহরণের জন্য ডেটা সেট আপ করতে ব্যবহৃত হয়, যেন আমরা শীঘ্রই দেখব।artist মেথডটি যেটি SDL Query রুট টাইপের সাথে ম্যাচ করে। artists এর জন্য একটি attr_reader ও যোগ করা হয়েছে। সেটি API-এ এক্সপোজ হবে শুধু SDL ডকুমেন্টে Query টাইপে সেটি ফিল্ড হিসেবে যোগ করলে।class Query attr_reader :artists def initialize(artists) @artists = artists end def artist(args={}) @artists[args['name']] end endquery ফিল্ড ইমপ্লিমেন্ট করে। ইনিশিয়ালাইজার কিছু ডেটা লোড করে টেস্টিং জন্য একটি ইন্ডি ব্যান্ডের জন্য নিউজিল্যান্ড থেকে যেটি আমি শুনতে পছন্দ করি।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/graphql HTTP রিকোয়েস্ট পাথের জন্য একটি হ্যান্ডলার ইনক্লুড করে এবং তারপর এটি স্টার্ট করা হয়।Agoo::Server.init(6464, 'root', thread_count: 1, graphql: '/graphql') Agoo::Server.start()$songs_sdl) এবং তারপর অ্যাপ্লিকেশন স্লিপ করে যতক্ষণ না সার্ভার রিকোয়েস্ট প্রসেস করে।Agoo::GraphQL.schema(Schema.new) { Agoo::GraphQL.load($songs_sdl) } sleep API ব্যবহার করা
curl ব্যবহার করতে পারেন।{ artist(name:"Fazerdaze") { name songs{ name duration } } } Fazerdaze চায় এবং name এবং songs রিটার্ন করে একটি JSON ডকুমেন্টে। প্রতিটি Song-এর জন্য name এবং duration রিটার্ন করা হয় একটি JSON অবজেক্টে। আউটপুট এইরকম দেখাবে।{ "data": { "artist": { "name": "Fazerdaze", "songs": [ { "name": "Jennifer", "duration": 240 }, { "name": "Lucky Girl", "duration": 170 }, { "name": "Friends", "duration": 194 }, { "name": "Reel", "duration": 193 } ] } } }curl- দিয়ে করা হলে সেই কন্টেন্ট রিটার্ন করবে।curl -w "\n" 'localhost:6464/graphql?query=\{artist(name:"Fazerdaze")\{name,songs\{name,duration\}\}\}&indent=2'duration-র বদলে release রিপ্লেস করুন এবং নোট করুন Ruby Time-এর JSON স্ট্রিং-এ কনভারশন।গানের শেষে