sanity-ruby

Ruby bindings for the Sanity API


License
MIT
Install
gem install sanity-ruby -v 0.5.0

Documentation

Sanity

Maintainability

The Sanity Ruby library provides convenient access to the Sanity API from applications written in Ruby. It includes a pre-defined set of classes for API resources.

The library also provides other features, like:

  • Easy configuration for fast setup and use.
  • A pre-defined class to help make any PORO a "sanity resource"
  • Extensibility in overriding the serializer for the API response results
  • A small DSL around GROQ queries

Contents

Getting Started

Add this line to your application's Gemfile:

gem 'sanity-ruby'

Setup your configuration. If using in Rails, consider setting this in an initializer:

Sanity.configure do |s|
  s.token = "yoursupersecrettoken"
  s.api_version = "v2021-03-25"
  s.project_id = "1234"
  s.dataset = "development"
  s.use_cdn = false
end

or you can set the following ENV variables at runtime:

SANITY_TOKEN="yoursupersecrettoken"
SANITY_API_VERSION="v2021-03-25"
SANITY_PROJECT_ID="1234"
SANITY_DATASET="development"
SANITY_USE_CDN="false"

The configuration object is thread safe meaning you can connect to multiple different projects across multiple threads. This may be useful if your application is interacting with multiple different Sanity projects.

To create a new document:

Sanity::Document.create(params: {_type: "user", first_name: "Carl", last_name: "Sagan"})

You can also return the created document ID.

res = Sanity::Document.create(params: {_type: "user", first_name: "Carl", last_name: "Sagan"}, options: {return_ids: true})

# JSON.parse(res.body)["results"]
# > [{"id"=>"1fc471c6434fdc654ba447", "operation"=>"create"}]

To create a new asset:

# TODO

To make any PORO a sanity resource:

class User < Sanity::Resource
  attribute :_id, default: ""
  attribute :_type, default: ""
  mutatable only: %i(create delete)
  queryable
  publishable
end

Since Sanity::Resource includes ActiveModel::Model and ActiveModel::Attributes, you're able to define types on attributes and use methods like alias_attribute.

class User < Sanity::Resource
  ...
  attribute :name, :string, default: 'John Doe'
  attribute :_createdAt, :datetime
  alias_attribute :created_at, :_createdAt
  ...
end

To create a new document in Sanity:

User.create(params: { first_name: "Carl", last_name: "Sagan" })

or if you need to validate the object in your application first:

user = User.new(first_name: "Carl", last_name: "Sagan")
# your business logic here...
user.create

To make any PORO act like a sanity resource:

class User
  include Sanity::Mutatable
  include Sanity::Queryable
  queryable
  mutatable
end

Serialization

When using a PORO, you can opt-in to automatically serialize your results. You must define all attributes that should be serialized.

class User < Sanity::Resource
  auto_serialize
  ...
end

Additionally, you can configure a custom serializer. See how to define a custom serializer below.

class User < Sanity::Resource
  serializer UserSerializer
  ...
end

Finally, at query time you can also pass in a serializer. A serializer specified at query time will take priority over any other configuration.

User.where(active: true, serializer: UserSerializer)

where UserSerializer might look like:

class UserSerializer
  class << self
    def call(...)
      new(...).call
    end
  end

  attr_reader :results

  def initialize(args)
    @results = args["result"]
  end

  def call
    results.map do |result|
      User.new(
        _id: result["_id"],
        _type: result["_type"]
      )
    end
  end
end

Mutating

To create a document:

Sanity::Document.create(params: {_type: "user", first_name: "Carl", last_name: "Sagan"})

To create or replace a document:

Sanity::Document.create_or_replace(params: { _id: "1234-321", _type: "user", first_name: "Carl", last_name: "Sagan"})

To create a document if it does not exist:

Sanity::Document.create_if_not_exists(params: { _id: "1234-321", _type: "user", first_name: "Carl", last_name: "Sagan"})

To delete a document:

Sanity::Document.delete(params: { _id: "1234-321"})

To patch a document:

Sanity::Document.patch(params: { _id: "1234-321", set: { first_name: "Carl" }})

Publishing

To publish a document:

Sanity::Document.publish(["1234-321"])

To unpublish a document:

Sanity::Document.unpublish(["1234-321", "1432432-545"])

Querying

To find document(s) by id:

Sanity::Document.find(id: "1234-321")

To find documents based on certain fields:

Where

majority supported

where: {
  _id: "123", # _id == '123'
  _id: {not: "123"} # _id != '123'
  title: {match: "wo*"} # title match 'wo*'
  popularity: {gt: 10}, # popularity > 10
  popularity: {gt_eq: 10}, # popularity >= 10
  popularity: {lt: 10}, # popularity < 10
  popularity: {lt_eq: 10}, # popularity <= 10
  _type: "movie", or: {_type: "cast"} # _type == 'movie' || _type == 'cast'
  _type: "movie", and: {or: [{_type: "cast"}, {_type: "person"}]} # _type == 'movie' && (_type == 'cast' || _type == 'person')
  _type: "movie", or: [{_type: "cast"}, {_type: "person"}] # _type == 'movie' || _type == 'cast' || _type == 'person'
}
Sanity::Document.where(_type: "user", and: {or: {_id:  "123", first_name: "Carl" }})
# Resulting GROQ:
# *[_type == 'user' && (_id == '123' || first_name == 'Carl')]

Order

partially supported

order: { createdAt: :desc, updatedAt: :asc }
# order(createdAt desc) | order(updatedAt asc)

Limit

limit: 5, offset: 10
Sanity::Document.where(_type: "user", limit: 5, offset: 2)

Select

partially supported

select: [:_id, :slug, :title, :name]
Sanity::Document.where(_type: "user", select: %i[first_name last_name])

Should you need more advanced querying that isn't handled in this gem's DSL you can pass a raw groq query

Query Cheat Sheet

groq_query = <<-GROQ
  *[ _type =='movie' && name == $name] {
    title,
    poster {
      asset-> {
        path,
        url
      }
    }
  }
GROQ

Sanity::Document.where(groq: groq_query, variables: {name: "Monsters, Inc."})

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake test to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install.

Testing across all supported versions:

To run tests across all gem supported ruby versions (requires Docker):

bin/dev-test

To run lint across all gem supported ruby versions (requires Docker):

bin/dev-lint

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/dvmonroe/sanity-ruby.

License

The gem is available as open source under the terms of the MIT License.