• Stars
    star
    107
  • Rank 323,587 (Top 7 %)
  • Language
    Ruby
  • License
    MIT License
  • Created about 9 years ago
  • Updated almost 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Connect Any App to Any Service

Gem Version Code Climate BuildStatus Test Coverage Gitter

Cangaroo

Cangaroo helps developers integrating their apps with any service. It is a Rails Engine that can be installed on any Rails application and is used as a connection hub from one or multiple applications and external services.

[TODO] add self-explanatory image here.

When/Why you should use Cangaroo?

Cangaroo allows to move the logic related to external services connection and synchronization between multiple applications.

This logic will reside in a shared area without the need to replicate it for any system component. It's especially useful when working with larger system formed by multiple applications that need to send messages to each other and to external services.

This kind of configuration allows:

  • don't overload your application resources allowing to scale the number of requests that can be handled;
  • in case of errors or downtimes of any system component, Cangaroo stores each message and retry sending it until it's successfully delivered;
  • use and contribute to a lot of integrations that has already be done by the community.

Integrations

Cangaroo integrations are pieces of code that allow interacting with external services via API.

An usual flow is:

  1. Cangaroo receives some data from an application;
  2. Data is sent to one or more integrations;
  3. Integrations convert data to be compatible with an external service API;
  4. Integrations send converted data to the external service.

Cangaroo is born with built-in Wombat extensions compatibility. All the old Wombat exensions have been migrated to the Cangaroo organization so that they can be maintained more easily.

The whole story

Some time ago Spree decided to shut down Wombat and to release its closed source code to customers only, so we had to decide how to go ahead, and the alternative were:

  1. hosting Wombat by ourselves for some of our clients
  2. starting a new open source project with an API compliant with Wombat.

We believe in open source so we chose the latter.

The idea is a bit different from Wombat, the goal of this project is to provide a backwards compatible API and give the developers the freedom to change and customize it.

If you're interested in hosting an admin interface similar in functionality to Wombat, check out the cangaroo_ui gem.

We hope this project can help to make the migration from Wombat easier and we believe the Spree/Solidus community will help to make it better.

Dependencies

  • rails (>= 4.2.4)

Installation

Cangaroo is a Rails Engine so as usual you can install it by using Bundler by adding it to your application's Gemfile:

  # Gemfile
  gem 'cangaroo'

And then executing:

$ bundle

Install the needed migration with:

$ bin/rake cangaroo:install:migrations

And then executing:

$ bin/rake db:migrate

Now mount the engine into your routes.rb file:

  # routes.rb
  ...
  mount Cangaroo::Engine => "/cangaroo"
  ...

Usage

First create a connection:

  Cangaroo::Connection.create(
    name: 'mystore',
    url: 'http://www.mystore.com',
    key: 'puniethahquoe5aisefoh9ci0Shuaniemei6jahx',
    token: 'ahsh8phuezu3xuhohs6kai5vaB1tae0wiy1shohp'
  )

then create a cangaroo job:

module Cangaroo
  class ShipmentJob < Cangaroo::Job
    connection :mystore
    path '/update_shipment'

    def perform?
      type == 'shipments' &&
      payload['status'] == 'shipped'
    end
  end
end

and add this job to the Rails.configuration.cangaroo.jobs:

  # config/initializers/cangaroo.rb

  Rails.configuration.cangaroo.jobs = [Cangaroo::ShipmentJob]

How it works

Cangaroo provides a Push API where you can send your data. After data has been received, Cangaroo sends data to integrations and webhooks based on your business logic.

This is the detailed flow:

  • Cangaroo receives the data
  • If some error like "wrong key and token" or "malformed json" is raised Cangaroo returns an HTTP status code based on the error type:
    • 406 for wrong request
    • 401 for Unauthorized
    • 500 for wrong json schema
    • 500 for Cangaroo internal errors
  • If there are no errors, for each object in the json body, Cangaroo checks what jobs must be enqueued by calling the #perform? method. Each job returning true to #perform? will be enqueued.

Push API

Cangaroo has just a single endpoint where you can push your data, based on where Cangaroo::Engine is mounted, it will be reachable under the /endpoint path. For example, if the Cangaroo::Engine is mounted under /cangaroo the Push API path will be /cangaroo/endpoint.

When you push to the endpoint the HTTP Request must respect this conventions:

  • It must be a POST request
  • It must be an application/json request so you have to set the Content-Type header to application/json
  • The request must have the X-Hub-Store and X-Hub-Access-Token headers set to a value that exists in the Cangaroo::Connection model (to learn more refer to the Connection documentation below)
  • The request body must be a well formatted json.

The json body contains data that will be processed by Cangaroo, the following is an example of an order that will be processed on Cangaroo:

{
  "orders": [
    {
      "id": "O154085346",
      "status": "complete",
      "email": "[email protected]"
    }
  ]
}

The root objects of the json body must contain an array with the objects that Cangaroo needs to process. The only required field for the objects contained in the arrays will be the id key. Push API also supports multiple objects so a request with the following body:

  {
     "orders":[
        {
           "id":"O154085346172",
           "state":"cart"
        },
        {
           "id":"O154085343224",
           "state":"payed"
        }
     ],
     "shipments":[
        {
           "id":"S53454325",
           "state":"shipped"
        },
        {
           "id":"S53565543",
           "state":"waiting"
        }
     ]
  }

will create 2 orders and 2 shipments.

When Cangaroo receives the request it responds with a 200(OK) HTTP status code and the response body will contain numbers of the objects in the payload, for example for the previous request the response will be:

  {
    "orders": 2,
    "shipments": 2
  }

if something goes wrong Cangaroo responds with an HTTP error code with an error message in the body, for example:

  {
    "error": "The property '#/orders/0' did not contain a required property of 'id' in schema"
  }

Connection

Connection are services that can send and receive data from Cangaroo. Each connection must have these fields:

  • name - (required, String) A generic name for this connection
  • url - (required, String) The url where Cangaroo pushes the data
  • key - (required, String) It's used for authentication (used to check the request's 'X-Hub-Store' header)
  • token - (required, String) It's used for authentication (used to check the request's 'X-Hub-Access-Token' header)
  • basic_auth - (optional, Boolean) Defaults to false. If you would like to use HTTP basic auth in your integration instead of Wombat's key + token. Basic auth is handled Stripe-style, without a username using key as your password.
  • parameters - (optional, Hash) Used as parameters when Cangaroo makes a request to this connection

For now we don't have a Web GUI so you have to create the connection on your own by running the code somewhere on your server, for example from the Rails console:

  Cangaroo::Connection.create(
    name: 'mystore',
    url: 'http://www.mystore.com',
    key: 'puniethahquoe5aisefoh9ci0Shuaniemei6jahx',
    token: 'ahsh8phuezu3xuhohs6kai5vaB1tae0wiy1shohp',
    parameters: {
      'channel': 'mysubstore'
    }
  )

Cangaroo Jobs

Jobs are where the payload is pushed to the configured connection.

To allow a job to be executed add it to the Rails.configuration.cangaroo.jobs configuration, for example in an initializer:

  # config/initializers/cangaroo.rb

  Rails.configuration.cangaroo.jobs = [Cangaroo::AddOrderJob, Cangaroo::UpdateShipmentJob]

The Cangaroo::Job class inherits from ActiveJob::Base, so you can use any 3rd-party queuing library supported by ActiveJob. When the job is performed Cangaroo makes a POST request to the connection with the configured path and build the json body with the result of the #transform instance method merged with this attributes:

  • request_id - is the job_id coming from ActiveJob::Base
  • parameters - are the parameters configured by the parameters class method

You can use the following Cangaroo::Job class methods to configure the job's behaivor:

  • connection - is the connection name (see connection for more info)
  • path - this path will be appended to your connection.url
  • parameters - these parameters will be merged with connection.parameters, they will be added to the json body.

it also has a #perform? instance method that must be implemented. This method must return true or false as Cangaroo will use it to understand if the job must be performed. Inside the #perform? method you'll be able to access the source_connection, type and payload instance attributes.

The #transform instance method can be overridden to customize the json body request, it will have the source_connection, type and payload variables (like the #perform? method) and must return an Hash.

The following is an example of a Cangaroo::Job:

  module Cangaroo
    class ShipmentJob < Cangaroo::Job
      connection :mystore
      path '/update_shipment'
      parameters({ timestamp: Time.now })

      def transform
        payload = super
        payload['shipment']['updated_at'] = Time.now
        payload
      end

      def perform?
        type == 'shipments' &&
        payload['status'] == 'shipped'
      end
    end
  end

Suppose that the mystore connection has a url set to "http://mystore.com" an the payload is something like:

  { "id": "S123", "status": "shipped" }

It will do a POST request to http://mystore.com/update_shipment with this json body:

{
  "request_id": "088e29b0ab0079560dea5d3e5aeb2f7868af661e",
  "parameters": {
    "timestamp": "2015-11-04 14:14:30 +0100"
  },
  "shipment": {
    "id": "S123",
    "status": "shipped"
  }
}

Tests

Tests are written using rspec and Appraisals

  • Run bundle exec appraisal install before running any specs
  • bundle exec rake will run the test suite for rails 4 and rails 5
  • bundle exec rspec will run specs for the latest rails version
  • if you want run specs only for for rails 4 run appraisal rails-4 rake, for rails 5 run appraisal rails-5 rake.

License

Cangaroo is copyright Β© 2016 Nebulab. It is free software, and may be redistributed under the terms specified in the license.

About

Nebulab

Cangaroo is funded and maintained by the Nebulab team.

We firmly believe in the power of open-source. Contact us if you like our work and you need help with your project design or development.

More Repositories

1

simple_command

A simple, standardized way to build and use Service Objects (aka Commands) in Ruby
Ruby
617
star
2

erb-formatter

Format ERB files with speed and precision
Ruby
140
star
3

pulsar

Manage your Capistrano deployments with ease
Ruby
129
star
4

spree-subscriptions

Spree extension to handle subscriptions
Ruby
86
star
5

reverse_coverage

A tool to find the test examples which cover a specific line (or set of lines) of a Ruby project
JavaScript
78
star
6

omnes

Pub/Sub for Ruby
Ruby
58
star
7

playbook

πŸ“– We are Nebulab, and this is how we work.
SCSS
53
star
8

prependers

Easily and cleanly extend third-party code.
Ruby
27
star
9

spree-one-page-checkout

Source code for One Page Checkout blog post
Ruby
24
star
10

runtime_config

A runtime configuration tool for Rails 5
Ruby
23
star
11

rails_console_toolkit

Configurable Rails Console Helpers
Ruby
20
star
12

umarell

All in one Ruby static code analyzer
Ruby
18
star
13

spree-ember-example

The example repository that goes with http://nebulab.it/blog/using-ember-js-with-spree/
Ruby
17
star
14

multitenant_shop

Solidus eCommerce with multitenancy
Ruby
11
star
15

spree-garbage-cleaner

A little gem that helps you cleanup old, unneeded data from a Spree database.
Ruby
11
star
16

erb-formatter-vscode

VSCode extension for ERB::Formatter (Format ERB files with speed and precision)
JavaScript
9
star
17

indago

Lightweight drop-in Ransack replacement without the ActiveRecord hackery.
Ruby
7
star
18

dev_tools

Contains useful gems to be used in development
Ruby
7
star
19

spree_return_authorizations_frontend

Adds a frontend interface to allow user to ask for items returns
Ruby
7
star
20

rails-vuejs-jsx

Products catalog Rails application moved to VueJS and JSX
Ruby
7
star
21

spree_simple_reports

JavaScript
6
star
22

dru

DRU - Docker-Compose Run Utility
Ruby
6
star
23

moonshine

Moonshine is a configuration driven method chain builder.
Ruby
5
star
24

cypress-store

An example of integrating Cypress with Rails.
Ruby
5
star
25

spree_ember_one_page_checkout

An ember.js application to add a one page checkout to Spree.
CoffeeScript
5
star
26

erb-linter

Check your ERB files for closing tags, indentation, bad attributes etc.
Ruby
5
star
27

renderful

A Ruby rendering engine for headless CMSs, with support for caching and Ruby on Rails.
Ruby
5
star
28

spree_order_constraints

A simple way to change the behaviour of checkout_allowed? to add some constraints to your customers as they proceed to checkout
Ruby
5
star
29

spree_exclusive_products

It filters variants depending on user roles
Ruby
5
star
30

solidus_shipwire

solidus and shipwire connect manager
Ruby
5
star
31

solidus_page_objects

An extension that adds site_prism page objects for common Solidus views
Ruby
4
star
32

solidus_client

Solidus eCommerce API Ruby client
Ruby
4
star
33

spree_one_page_add_to_cart

Spree one page add to cart for fast checkout
Ruby
4
star
34

soliton

An Ember application to search for Solidus extensions on GitHub
JavaScript
4
star
35

solidus_nextjs_frontend

JavaScript
4
star
36

baywatch

Rescue projects before they sink: easy 1-container feature branch previews with Docker
Dockerfile
4
star
37

spree-api-client.js

JavaScript
4
star
38

minitest-shopify

Ruby
4
star
39

wombat_migration

Useful to share info about how to migrate wombat
3
star
40

bretelline

Nebulab's Rails (and Solidus) application template.
Ruby
3
star
41

create-hydrogen

JavaScript
2
star
42

workflow

A repo useful to simulate a basic features management workflow
2
star
43

spree_line_item_discount

Adds the ability to create a different discount in percentage for each item in the cart with the same coupon code
Ruby
2
star
44

spree_multiple_notifications

Ruby
2
star
45

nebulab.github.io

The Nebulab website
HTML
2
star
46

easy_maintenance

Easy maintenance page for your apps
Ruby
2
star
47

klarna_proxy

Ruby Klarna proxy gem that consumes the Klarna APIs: https://developers.klarna.com/api/
Ruby
2
star
48

rails-sales-taxes-kata

One of the exercises used in our internal academy.
2
star
49

solidus_bot

A simple chatbot which search products on a solidus store
Ruby
1
star
50

spree_social_promotions

Ruby
1
star
51

products_feed

Easy products feed generator
Ruby
1
star
52

solidus_product_uploads

Ruby
1
star
53

circleci-orbs-stoplight

πŸ“œ An Orb for linking your Git repository to a Stoplight project.
1
star
54

docker-preview-server

Chef cookbooks to spin up a docker preview server.
Ruby
1
star
55

helen

Helen - Office Automation
1
star
56

heroku-ruby-docker

A docker image to mimic Heroku Ruby environment
Dockerfile
1
star
57

solidus_frontend_examples

Example custom frontend applications built on Solidus's GraphQL API
JavaScript
1
star
58

spree_allow_shipping_methods

Ruby
1
star
59

html5-boilerplate-stasis

JavaScript
1
star
60

backport

Manage your backported code with ease.
Ruby
1
star
61

segmentation

The missing SDK for integrating Segment in your Ruby on Rails application.
Ruby
1
star
62

pulsar-conf-demo

Example of pulsar-conf repository
Ruby
1
star
63

spree-invite-a-friend-example

Ruby
1
star
64

circleci-orbs-feature-branch-preview

πŸ‘“ An Orb to preview PRs on a specific server using Docker
1
star
65

products_catalog

Simple app Rails APIs with VueJS JSX for the Ruby day Workshop
Ruby
1
star
66

cangaroo_tutorial

Example application on how to setup Cangaroo to tweet every time a new product is created
Ruby
1
star
67

darkstore

Darkstore API gem
Ruby
1
star
68

solidus-on-heroku

Deploy your solidus app on heroku like a boss
Ruby
1
star
69

aws-solidus-demo-opsworks_cookbook

Chef 13 cookbook with Opsworks and NodeJS for AWS Rails deployment
Ruby
1
star