= Dapr Client for Ruby :icons: font ifdef::env-github[] :tip-caption: :bulb: :note-caption: :information_source: :important-caption: :heavy_exclamation_mark: :caution-caption: :fire: :warning-caption: :warning: endif::[] :dapr-building-block: https://docs.dapr.io/concepts/building-blocks-concept/[Dapr Building Block] :pubsub-block: https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-overview/[Dapr Pub/Sub Building Block] :state-block: https://docs.dapr.io/developing-applications/building-blocks/state-management/state-management-overview/[Dapr State Management Building Block] :actors-block: https://docs.dapr.io/developing-applications/building-blocks/actors/actors-overview/[Dapr Actor Building Block] :binding-block: https://docs.dapr.io/developing-applications/building-blocks/bindings/bindings-overview/[Dapr Binding Building Block] :secret-block: https://docs.dapr.io/developing-applications/building-blocks/secrets/secrets-overview/[Dapr Secret Building Block] :configuration-block: https://docs.dapr.io/developing-applications/building-blocks/configuration/configuration-api-overview/[Dapr Configuration Building Block] :distributed-lock-block: https://docs.dapr.io/developing-applications/building-blocks/distributed-lock/distributed-lock-api-overview/[Dapr Distributed Lock Building Block] :workflow-block: https://docs.dapr.io/developing-applications/building-blocks/workflow/workflow-overview/[Dapr Workflow Building Block] :cryptography-block: https://docs.dapr.io/developing-applications/building-blocks/cryptography/cryptography-overview/[Dapr Cryptography Building Block] image::https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg[Conventional Commits,link=https://www.conventionalcommits.org/en/v1.0.0/] == Overview This library provides an interface to the {dapr-building-block}s. CAUTION: This is a work in progress and is not yet ready for production use. NOTE: Documentation will be added as this library matures. == Installation Install the gem and add it to the application's Gemfile by executing: $ bundle add dapr --require dapr/client If bundler is not being used to manage dependencies, install the gem by executing: $ gem install dapr .Example from Gemfile [source,ruby] ---- gem 'dapr', '~> 0.4', require: 'dapr/client' gem 'datadog_api_client' gem 'grpc', force_ruby_platform: true ---- === Docker If you find yourself waiting 20 minutes to build the grpc gem in your CI environments, you might want to use the images we publish (built from https://docker.io/library/ruby images) .Example Dockerfile [source,docker] ---- FROM ghcr.io/rubyists/dapr-ruby-client:0.4.2-ruby3.3.6-alpine3.21 RUN ... ---- == Usage Dapr being such a Smörgåsbord, this library exposes each {dapr-building-block} as either a Client or a Service, depending on whether it uses the AppCallback runtime (Service) or the Dapr API (Client). The clients are thin wrappers around the Dapr API, while the service implementations will be more opinionated, higher-level abstractions. See the specific section on the building block you are interested in for its usage information. == Building Blocks === Namespace Convention In order to avoid conflicts with any other `Dapr` top level namespace(s), Each {dapr-building-block} is exposed as a class under the `Rubyists::Dapr::Client` or `Rubyists::Dapr::Service` namespace. === Pub/Sub Implementation of {pubsub-block} ==== Publish a message [source,ruby] ---- require 'dapr/client/publisher' ENV['DAPR_GRPC_PORT'] = '3500' <1> publisher = Rubyists::Dapr::Client::Publisher.new('pubsub-name') <2> publisher.publish('topic-name', { message: 'Hello, Dapr!', from: 'Ruby' }) <3> ---- <1> Set the Dapr gRPC port to the Dapr runtime port. (This is automatically set in kubernetes environments) <2> Create a new publisher for the `pubsub-name` pubsub component. This component must be defined in the Dapr runtime. <3> Publish a message to the `topic-name` topic. The message can be any Ruby object that can be serialized to JSON. + TIP: JSON is our default serializer. To use a different serializer, you can pass a `serializer:` argument to the publisher's initializer ==== Subscribe to topics Subscriptions in Dapr work a little differently than you may be used to. Instead of subscribing to a topic then looping through consumed messages, you define a fully-fledged service that Dapr will send each message to in the topic(s) that you specify. This unique approach allows you to focus on the business logic of your service, rather than the plumbing of message consumption. [source,ruby] ---- require 'dapr/service/subscriber' handler = ->(event) { puts "Got event: #{event}" } <1> pubsub_name = 'pubsub-name' <2> topics = 'TOPIC-A' <3> sub = Rubyists::Dapr::Service::Subscriber.new(pubsub_name:, topics:, handler:) <4> sub.start! <5> ---- <1> Define a handler that will be called for each message received. `event` will be a `CloudEvents::Event` instance. + NOTE: The handler can be anything that responds to `#call`, such as a lambda, proc, or instance. Sky's the limit! (Dependency injection, anyone?) + <2> The name of the Dapr pubsub component this subscriber will utilize. <3> The name of the topic(s) to subscribe to. + TIP: Multiple topics can be subscribed to simultaneously by passing an array of topic names to the `topics` argument. + <4> Create a new subscriber for the `pubsub-name` pubsub component, subscribing to the `TOPIC-A` topic. <5> Start the subscriber. This will block the current thread and call the handler for each message received. === State Management Implementation of {state-block} ==== Set state key(s) [source,ruby] ---- require 'dapr/client/state' <1> desired_state = { key1: 'value1', key2: { nested: 'value2' }.to_json } <2> Rubyists::Dapr::Client::State.set(desired_state) <3> ---- <1> Require the state client. <2> Define the desired state. This must be a hash with simple keys, and the values must be strings (thus the #to_json) <3> Set the state. This will overwrite any existing state with the same key(s) (and update the etag of any updated keys) ==== Get state key(s) [source,ruby] ---- require 'dapr/client/state' <1> states = Rubyists::Dapr::Client::State.get('key1', 'key2') <2> puts states['key1'].data <3> ---- <1> Require the state client. <2> Get the state for the specified key(s). This will return a hash whose values respond to #data. <3> Access the data of the state for the `key1` key. === Actors Implementation of {actors-block} === Bindings Implementation of {binding-block} === Secrets Implementation of {secret-block} === Configuration Implementation of {configuration-block} [source,ruby] ---- require 'dapr/client/configuration' value = Rubyists::Dapr::Client::Configuration.get('TEST_KEY') ---- === Distributed Lock Implementation of {distributed-lock-block} [source,ruby] ---- require 'dapr/client/lock' lock = Rubyists::Dapr::Client::Lock.acquire('TEST_LOCK') ... do_important_stuff ... lock.unlock! ---- === Workflow Implementation of {workflow-block} === Cryptography Implementation of {cryptography-block} == Development After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. To install this gem on your local machine, run `bundle exec rake install`. Releases are handled by release-please in github actions. == Contributing Bug reports and pull requests are welcome on GitHub at https://github.com/rubyists/dapr-ruby-client. === Conventional Commits This project uses Conventional Commits for commit messages. Please follow the guidelines at https://www.conventionalcommits.org/en/v1.0.0/[conventionalcommits.org]. === Overcommit This project uses https://github.com/sds/overcommit[overcommit] to enforce repository policies. Please ensure you have it installed and configured before contributing. tl;dr;: `overcommit --install && overcommit --sign`