package

github.com/masak1yu/google-api-client-cr

0.1.2 / published Mar 15, 2026 / repository

A Crystal client for the Google YouTube Data API v3. Ported from google-api-ruby-client with full API coverage (83 methods). Includes retry/backoff, pagination, batch requests, resumable upload, OAuth2/Service Account auth, and token persistence.

google-api-client-cr

CI

A Crystal client for the Google YouTube Data API v3, ported from google-api-ruby-client.

Features

  • YouTube Data API v3 full coverage (83 methods)
  • Type-safe response models with JSON::Serializable (127 classes)
  • API Key, OAuth2, and Service Account (JWT) authentication
  • Token persistence (save/load credentials to file)
  • File upload (multipart + resumable) and download support
  • Batch requests (up to 50 API calls in one HTTP request)
  • Automatic retry with exponential backoff on 429/5xx errors
  • Pagination helper for iterating over all result pages

Supported Resources

ResourcelistinsertupdatedeleteOther
Searcho
Videosoooorate, getRating, reportAbuse, getTrainability
ChannelsooinsertBanner
Playlistsoooo
PlaylistItemsoooo
PlaylistImagesoooo
CommentsoooomarkAsSpam, setModerationStatus
CommentThreadsooo
Subscriptionsooo
Captionsoooodownload
ChannelSectionsoooo
Activitieso
LiveBroadcastsoooobind, transition, insertCuepoint
LiveStreamsoooo
LiveChatMessagesoootransition, stream
LiveChatModeratorsooo
LiveChatBansoo
Watermarkssetunset
Thumbnailsset
Memberso
MembershipsLevelso
SuperChatEventso
VideoCategorieso
VideoAbuseReportReasonso
ThirdPartyLinksoooo
AbuseReportso
I18nLanguageso
I18nRegionso

Installation

Add this to your application's shard.yml:

dependencies:
  google-api-client-cr:
    github: masak1yu/google-api-client-cr

Usage

API Key (read-only public data)

require "google-api-client-cr"

youtube = Google::Apis::YoutubeV3::YouTubeService.new
# Set API_KEY environment variable or:
# youtube.key = "YOUR_API_KEY"

# Search
results = youtube.list_searches("snippet", q: "Crystal programming", max_results: 5, type: "video")
results.items.try &.each do |item|
  puts "#{item.snippet.try &.title} (#{item.id.try &.video_id})"
end

# Video details
videos = youtube.list_videos("snippet,statistics", id: "VIDEO_ID")
videos.items.try &.each do |video|
  puts "#{video.snippet.try &.title}: #{video.statistics.try &.view_count} views"
end

# Channel info
channels = youtube.list_channels("snippet,statistics", for_username: "GoogleDevelopers")
channels.items.try &.each do |ch|
  puts "#{ch.snippet.try &.title}: #{ch.statistics.try &.subscriber_count} subscribers"
end

# Playlists
playlists = youtube.list_playlists("snippet", channel_id: "CHANNEL_ID", max_results: 10)
playlists.items.try &.each do |pl|
  puts pl.snippet.try &.title
end

# Comments
threads = youtube.list_comment_threads("snippet", video_id: "VIDEO_ID", max_results: 10)
threads.items.try &.each do |thread|
  comment = thread.snippet.try &.top_level_comment.try &.snippet
  puts "#{comment.try &.author_display_name}: #{comment.try &.text_display}"
end

OAuth2 (authenticated operations)

require "google-api-client-cr"

# 1. Create OAuth2 client
oauth = Google::Auth::OAuth2Client.new(
  client_id: ENV["CLIENT_ID"],
  client_secret: ENV["CLIENT_SECRET"]
)

# 2. Get authorization URL
url = oauth.authorization_url(scope: Google::Auth::Scopes::YOUTUBE)
puts "Visit: #{url}"

# 3. Exchange code for token
print "Enter code: "
code = gets.try(&.strip).not_nil!
oauth.authorize(code)

# 4. Use with service
youtube = Google::Apis::YoutubeV3::YouTubeService.new
youtube.authorize(oauth)

# Now you can use write operations
playlist = Google::Apis::YoutubeV3::Playlist.from_json(%({
  "snippet": { "title": "My Playlist", "description": "Created with Crystal" },
  "status": { "privacyStatus": "private" }
}))
created = youtube.insert_playlist("snippet,status", playlist)
puts "Created playlist: #{created.id}"

Service Account (server-to-server)

require "google-api-client-cr"

creds = Google::Auth::ServiceAccountCredentials.from_json_key(
  "service-account-key.json",
  scope: Google::Auth::Scopes::YOUTUBE_READONLY
)

youtube = Google::Apis::YoutubeV3::YouTubeService.new
youtube.authorize(creds)

Token Persistence

# Save credentials after authorization
oauth.save_credentials("tokens.json")

# Restore in a later session
oauth = Google::Auth::OAuth2Client.from_credentials(
  "tokens.json", client_id: ENV["CLIENT_ID"], client_secret: ENV["CLIENT_SECRET"]
)

Batch Requests

youtube.batch do |batch|
  batch.add("GET", "/youtube/v3/videos?part=snippet&id=VIDEO1") do |response|
    puts response.body
  end
  batch.add("GET", "/youtube/v3/videos?part=snippet&id=VIDEO2") do |response|
    puts response.body
  end
end

Pagination

first_page = youtube.list_searches("snippet", q: "Crystal", max_results: 50)
iterator = Google::Apis::Core::PageIterator.new(first_page) do |token|
  youtube.list_searches("snippet", q: "Crystal", max_results: 50, page_token: token)
end
iterator.each do |page|
  page.items.try &.each { |item| puts item.snippet.try &.title }
end

Requirements

  • Crystal >= 1.19.0

License

MIT

Contributors

API