Project

thron

0.0
No commit activity in last 3 years
No release in over 3 years
Thron APIs ruby client
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.10
~> 5.9
~> 10.0
~> 1.2

Runtime

~> 2.0
 Project Readme

Table of Contents

  • Warning
  • Scope
  • Setup
  • HTTPArty
  • Architecture
    • Gateways
      • Routing
      • Paginator
    • Response
    • Dynamic Entities
    • User Aggregate
  • Interface
    • Access
    • Contents
    • Groups
    • Categories
    • Disguise

Warning

I do not maintain this gem anymore. Please do copy with latest Thron APIs and integrate them into this facade if you need to use it.

Scope

This gem provides a simple Ruby client for the Thron (ex 4me) APIs. The aim of this gem is to provide a simple interface for your ruby application that need to communicate with Thron services. I've also managed to keep the gem's dependencies footprint as small as possible (i hate bulky Gemfile...).

Setup

This gem use at least a Ruby 2.1 compatible parser.
Thron is a payment service, is assumed you have a valid account in order to use this gem.
Once you have valid credentials to access the Thron APIs, you have to enter the THRON_CLIENT_ID value inside of your .env file, this way the gem can reads from it and configure itself properly.

HTTParty

This gem uses the HTTParty library to communicate with the Thron APIs. HTTParty has proven to be reliable and simple, so it's a natural candidate.

Architecture

This gem is architected on these concepts:

Gateways

Several gateways objects are used to communicate with the Thron APIs: each of them mimic the original Thron API namespace (find a complete list on Thron site). Each gateway derive from a basic class, which includes the HTTParty interface.

Routing

A simple routing engine is encapsulated into the gateway objects: a class-level hash declares the routes that matches the API name, by specifying the format and verb.
Some extra parameters are used to factory the route URL, in some cases lazily (by returning a proc object), since some APIs need to access the method arguments early to compose the URL.

Paginator

Thron APIs that return a list of results are limited to a maximum of 50.
To avoid repeating the same call many times by passing an augmented offset, is possible to call a wrapper method on the gateway objects that returns a paginator object. Once the paginator is loaded, it allows to navigate the results by using the following interface:

  • next: loads the first offset and move forward, returning last when max offset is reached
  • prev: move backwards from the current offset, returning first when minimum offset is reached
  • preload: does not move the offset, but indeed preload the specified number of data by performing an asynchronous call (wrapped in a thread).

Paginator keeps an internal cache to avoid hitting the remote service more than once. The same is used when preloading results. Keep that in mind when you need to get fresh data.

Response

The HTTParty response has been wrapped in order to return a logical object that wraps the APIs return values.
The main attributes are:

  • http_code: the HTTP code of the response
  • body: the body of the response, in case the result is JSON data, it contains the data parsed into an appropriate entity (read below)
  • total: in case the API returns a list of results, it indicates the total number of records; it's used by paginator
  • error: the error message, if any, returned by the API

Dynamic Entities

Some of the Thron APIs return a JSON representation of an entity. I have initially considered wrapping each entity into its own PORO object, but gave up after few days since the quality of the returned entities is very large.
I opted instead to wrap returned data into a sub-class of the OpenStruct object, having the same dynamic behaviour while adding some sugar features:

  • it converts the lower-camel-case parameters into (more rubesque) snake-case
  • it does recursive mapping of nested attributes
  • it converts time and date values to appropriate Ruby objects
    The same object can be used when passing complex parameters to some of the APIs: in this case is sufficent to call the #to_payload method on the entity to convert the object in an hash with lower-camle-case keys (see examples below).

User Aggregate

To avoid accessing the multitude of Thron APIs via several objects, an aggregate has been created (DDD anyone?).
The User aggregate delegates most of its methods directly to the gateway objects (it uses the Forwardable module). It keeps a registry of the gateway objects in order to refresh them on login: this is requested to update the token id that identifies the current session and that is stored internally by the gateway objects.

To create the user aggregate simply instantiate it without arguments:

user = Thron::User::new

Interface

The following examples illustrates how to use this library. Thron APIs include a broad range of methods, for a complete list of them please consult the official APIs documentation.
For the APIs that accepts composed arguments simply use the dynamic entity described above: just be aware to name its attributes by snake-case and not as the lower-camel-case specified in the Thron documentation.

Access

To get a valid session token just login with your credentials:

user.login(username: '<your_username>', password: '<your_password>')

From here you can check current user with the available methods, for example:

user.validate_token

Or you can query the APIs to return other details:

user.user_detail(username: '<a_username>')

Uploads the avatar image for a user (it relies on Linux file system call):

avatar = Thron::Entity::Image::new(path: '<path_to_an_image>').to_payload
user.update_image(username: '<a_username>', image: avatar)

Contents

Thron is all about managing users contents, so no surprise there is a plethora of methods at your disposal:

Find the contents by using the paginator object:

paginator = user.find_contents_paginator
paginator.preload(10) # preload the first 10 calls
paginator.next        # fetch first result set from preloaded cache

Show the contents by category (slightly more efficient):

user.show_contents(category_id: '<a_category_id>')

Load specific content detail:

user.content_detail(content_id: '<a_content_id>')

Groups

Users are arranged into different groups.

Create a new group:

group = Thron::Entity::Base::new(active: true, name: 'my new group').to_payload
user.create_group(data: group)

List existing groups:

paginator = user.find_gropus
paginator.next

Categories

Thron contents are organized by categories.

List existing categories (without paginator):

user.find_categories

Create a new locale for a category:

locale = Thron::Entity::Base::new(name: 'photos', description: 'JPG and PNG images', locale: 'EN').to_payload
user.create_category_locale(category_id: '<a_category_id>', locale: locale)

Disguise

Thron APIs allow to disguise another user via its apps sub-system.

Disguising only works inside the block:

user.disguise(app_id: '<app_id_that_can_disguise>', username: '<username_to_disguise>') do
  # load the disguised user contents, each gateway will now use the disguised token id
  contents = user.find_contents
  # do something with contents
end
# finished disguising, it returns disguised token id