https://github.com/solidusio/solidus_webhooks
Add support for incoming webhooks to your Solidus store.
https://github.com/solidusio/solidus_webhooks
hacktoberfest solidus solidus-extensions
Last synced: 6 months ago
JSON representation
Add support for incoming webhooks to your Solidus store.
- Host: GitHub
- URL: https://github.com/solidusio/solidus_webhooks
- Owner: solidusio
- License: bsd-3-clause
- Created: 2020-05-08T13:29:02.000Z (over 5 years ago)
- Default Branch: main
- Last Pushed: 2023-10-05T13:15:37.000Z (over 2 years ago)
- Last Synced: 2025-07-08T08:21:27.994Z (6 months ago)
- Topics: hacktoberfest, solidus, solidus-extensions
- Language: Ruby
- Homepage: http://solidus.io
- Size: 76.2 KB
- Stars: 7
- Watchers: 12
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Solidus Webhooks
[](https://circleci.com/gh/solidusio/solidus_webhooks)
[](https://codecov.io/gh/solidusio/solidus_webhooks)
## Installation
Add solidus_webhooks to your Gemfile:
```ruby
gem 'solidus_webhooks'
```
Bundle your dependencies and run the installation generator:
```shell
bin/rails generate solidus_webhooks:install
```
## Usage
A Webhook receiver is just a callable and can be registered in the Solidus configuration as follows:
```ruby
SolidusWebhooks.config.register_webhook_handler :tracking_number, -> payload {
order = Spree::Order.find_by!(number: payload[:order])
shipment = order.shipments.find_by!(number: payload[:shipment])
shipment.update!(tracking: payload[:tracking])
}
```
This will enable sending `POST` requests to `/webhooks/tracking-number` with a JSON payload like this:
```json
{
"order": "R1234567890",
"shipment": "S1234567890",
"tracking": "T123-456-789"
}
```
### Handlers requirements
The only requirement on handlers is for them to respond to `#call` and accept a payload.
Example:
```ruby
module TrackingNumberHandler
def self.call(payload)
order = Spree::Order.find_by!(number: payload[:order])
shipment = order.shipments.find_by!(number: payload[:shipment])
shipment.update!(tracking: payload[:tracking])
end
end
SolidusWebhooks.config.register_webhook_handler :tracking_number, TrackingNumberHandler
```
### Making the handler asynchronous
To make a handler asynchronous just make its implementation internally call your preferred job handler (e.g. ActiveJob). In most cases you'll want to filter, prepare, and validate the payload for the job of your choice, to avoid ingesting and invalid input.
Example:
```ruby
SolidusWebhooks.config.register_webhook_handler :tracking_number, -> payload {
UpdateTrackingNumberJob.perform_later(
order: payload.fetch(:order)
shipment: payload.fetch(:shipment)
tracking: payload.fetch(:tracking)
)
}
```
### Payload routing
If your handler can receive different kind of payloads the most common technique is to route them to appropriate sub-handlers (that can be an ActiveJob class or a service class).
```ruby
SolidusWebhooks.config.register_webhook_handler :tracking_number, -> payload {
case payload[:tracking]
when /^FOO(\d+-)+/
UpdateFooTrackingNumberJob.perform_later(
order: payload.fetch(:order)
shipment: payload.fetch(:shipment)
tracking: payload.fetch(:tracking)
)
when /^BAR(\d+-)+/
UpdateBarTrackingNumberJob.perform_later(
order: payload.fetch(:order)
shipment: payload.fetch(:shipment)
tracking: payload.fetch(:tracking)
)
else raise "unknown tracking service"
end
}
```
### Restricting Permissions
It's good practice not to use admin-user tokens for webhooks, instead you should define a permission set tied to the webhook handler you're providing. Use the standard Solidus permission-sets to do that.
Example:
```ruby
module ReceiveTrackingWebhookPermission < Spree::PermissionSets::Base
def activate!
can :receive, Spree::Webhook do |webhook|
webhook.id == :tracking_number
end
end
end
Spree::RoleConfiguration.configure do |config|
config.assign_permissions :foo_tracking_service, %w[
ReceiveTrackingWebhookPermission
]
end
```
### Accessing the API User
If you need to access the API user that is making the call to the webhook, you can just accept an additional argument in the callable handler.
Example:
```ruby
SolidusWebhooks.config.register_webhook_handler :tracking_number, -> payload, user {
Rails.logger.info "Received payload from user #{user.email}: #{payload.to_json}"
# …
}
```
## Development
### Testing the extension
First bundle your dependencies, then run `bin/rake`. `bin/rake` will default to building the dummy
app if it does not exist, then it will run specs. The dummy app can be regenerated by using
`bin/rake extension:test_app`.
```shell
bin/rake
```
To run [Rubocop](https://github.com/bbatsov/rubocop) static code analysis run
```shell
bundle exec rubocop
```
When testing your application's integration with this extension you may use its factories.
Simply add this require statement to your spec_helper:
```ruby
require 'solidus_webhooks/factories'
```
### Running the sandbox
To run this extension in a sandboxed Solidus application, you can run `bin/sandbox`. The path for
the sandbox app is `./sandbox` and `bin/rails` will forward any Rails commands to
`sandbox/bin/rails`.
Here's an example:
```
$ bin/rails server
=> Booting Puma
=> Rails 6.0.2.1 application starting in development
* Listening on tcp://127.0.0.1:3000
Use Ctrl-C to stop
```
### Updating the changelog
Before and after releases the changelog should be updated to reflect the up-to-date status of
the project:
```shell
bin/rake changelog
git add CHANGELOG.md
git commit -m "Update the changelog"
```
### Releasing new versions
Please refer to the dedicated [page](https://github.com/solidusio/solidus/wiki/How-to-release-extensions) on Solidus wiki.
## License
Copyright (c) 2020 Nebulab srls, released under the New BSD License.