{"id":17679973,"url":"https://github.com/costajob/thron","last_synced_at":"2026-06-20T21:31:06.937Z","repository":{"id":59158627,"uuid":"43064365","full_name":"costajob/thron","owner":"costajob","description":"Thron APIs Ruby client","archived":false,"fork":false,"pushed_at":"2016-09-22T13:25:00.000Z","size":299,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-05T15:36:48.721Z","etag":null,"topics":["cdn","ruby","thron-apis","thron-client"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/costajob.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-09-24T12:05:30.000Z","updated_at":"2018-11-29T11:15:47.000Z","dependencies_parsed_at":"2022-09-13T20:10:24.168Z","dependency_job_id":null,"html_url":"https://github.com/costajob/thron","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/costajob/thron","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/costajob%2Fthron","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/costajob%2Fthron/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/costajob%2Fthron/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/costajob%2Fthron/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/costajob","download_url":"https://codeload.github.com/costajob/thron/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/costajob%2Fthron/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34586666,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cdn","ruby","thron-apis","thron-client"],"created_at":"2024-10-24T09:04:58.521Z","updated_at":"2026-06-20T21:31:06.889Z","avatar_url":"https://github.com/costajob.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Table of Contents\n* [Warning](#warning)\n* [Scope](#scope)\n* [Setup](#setup)\n* [HTTPArty](#httparty)\n* [Architecture](#architecture)\n  * [Gateways](#gateways)\n    * [Routing](#routing)\n    * [Paginator](#paginator)\n  * [Response](#response)\n  * [Dynamic Entities](#dynamic-entities)\n  * [User Aggregate](#user-aggregate)\n* [Interface](#interface)\n  * [Access](#access)\n  * [Contents](#contents)\n  * [Groups](#groups)\n  * [Categories](#categories)\n  * [Disguise](#disguise)\n\n## Warning\nI 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.\n\n## Scope\nThis gem provides a simple Ruby client for the [Thron](https://developer.4me.it/index.php) (ex 4me) APIs.\nThe aim of this gem is to provide a simple interface for your ruby application\nthat need to communicate with Thron services. \nI've also managed to keep the gem's dependencies footprint as small as possible (i\nhate bulky Gemfile...).\n\n## Setup\nThis gem use at least a **Ruby 2.1** compatible parser.  \nThron is a payment service, is assumed you have a valid account in order to use this gem.  \nOnce you have valid credentials to access the Thron APIs, you have to enter the **THRON_CLIENT_ID** value\ninside of your *.env* file, this way the gem can reads from it and configure itself properly.\n\n## HTTParty\nThis gem uses the [HTTParty](https://github.com/jnunemaker/httparty) library to communicate with the Thron APIs.\nHTTParty has proven to be reliable and simple, so it's a natural candidate.\n\n## Architecture\nThis gem is architected on these concepts:\n\n### Gateways\nSeveral gateways objects are used to communicate with the Thron APIs: each of them\nmimic the original Thron API namespace (find a complete list on Thron site).\nEach gateway derive from a basic class, which includes the HTTParty interface.\n\n#### Routing\nA simple routing engine is encapsulated into the gateway objects: a class-level\nhash declares the routes that matches the API name, by specifying the\nformat and verb.  \nSome 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.\n\n#### Paginator\nThron APIs that return a list of results are limited to a maximum of **50**.  \nTo avoid repeating the same call many times by passing an augmented offset, \nis possible to call a wrapper method on the gateway objects that returns a paginator object.\nOnce the paginator is loaded, it allows to navigate the results by using the following interface:\n* **next**: loads the first offset and move forward, returning last when max offset is reached\n* **prev**: move backwards from the current offset, returning first when minimum offset is reached\n* **preload**: does not move the offset, but indeed preload the specified number of\n  data by performing an asynchronous call (wrapped in a thread).\n\nPaginator keeps an internal cache to avoid hitting the remote service more than\nonce. The same is used when preloading results. Keep that in mind when you need to get fresh data.\n\n### Response\nThe HTTParty response has been wrapped in order to return a logical object that wraps the APIs return values.  \nThe main attributes are:\n* http_code: the HTTP code of the response\n* body: the body of the response, in case the result is JSON data, it contains the data parsed into an appropriate entity (read below)\n* total: in case the API returns a list of results, it indicates the total number of records; it's used by paginator\n* error: the error message, if any, returned by the API\n\n### Dynamic Entities\nSome of the Thron APIs return a JSON representation of an entity. I have initially\nconsidered wrapping each entity into its own PORO object, but gave up after few\ndays since the quality of the returned entities is very large.  \nI opted instead to wrap returned data into a sub-class of the OpenStruct object, having the same\ndynamic behaviour while adding some sugar features:\n* it converts the lower-camel-case parameters into (more rubesque) snake-case\n* it does recursive mapping of nested attributes\n* it converts time and date values to appropriate Ruby objects  \nThe 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\nto convert the object in an hash with lower-camle-case keys (see examples below).\n\n### User Aggregate\nTo avoid accessing the multitude of Thron APIs via several objects, an aggregate has been created (DDD anyone?).  \nThe **User** aggregate delegates most of its methods directly to the gateway objects (it uses the *Forwardable* module).\nIt keeps a registry of the gateway objects in order to refresh them on login: this\nis requested to update the token id that identifies the current session and that is\nstored internally by the gateway objects.\n\nTo create the user aggregate simply instantiate it without arguments:\n```ruby\nuser = Thron::User::new\n```\n\n## Interface\nThe following examples illustrates how to use this library.\nThron APIs include a broad range of methods, for a complete list of them please  consult the [official APIs documentation](https://developer.thron.com/index.php).  \nFor the APIs that accepts composed arguments simply use the dynamic entity described\nabove: just be aware to name its attributes by snake-case and not as the \nlower-camel-case specified in the Thron documentation.\n\n### Access\nTo get a valid session token just login with your credentials:\n```ruby\nuser.login(username: '\u003cyour_username\u003e', password: '\u003cyour_password\u003e')\n```\nFrom here you can check current user with the available methods, for example:\n```ruby\nuser.validate_token\n```\nOr you can query the APIs to return other details:\n```ruby\nuser.user_detail(username: '\u003ca_username\u003e')\n```\nUploads the avatar image for a user (it relies on Linux *file* system call):\n```ruby\navatar = Thron::Entity::Image::new(path: '\u003cpath_to_an_image\u003e').to_payload\nuser.update_image(username: '\u003ca_username\u003e', image: avatar)\n```\n\n### Contents\nThron is all about managing users contents, so no surprise there is a plethora of\nmethods at your disposal:\n\nFind the contents by using the paginator object:\n```ruby\npaginator = user.find_contents_paginator\npaginator.preload(10) # preload the first 10 calls\npaginator.next        # fetch first result set from preloaded cache\n```\nShow the contents by category (slightly more efficient):\n```ruby\nuser.show_contents(category_id: '\u003ca_category_id\u003e')\n```\nLoad specific content detail:\n```ruby\nuser.content_detail(content_id: '\u003ca_content_id\u003e')\n```\n\n### Groups\nUsers are arranged into different groups.\n\nCreate a new group:\n```ruby\ngroup = Thron::Entity::Base::new(active: true, name: 'my new group').to_payload\nuser.create_group(data: group)\n```\nList existing groups:\n```ruby\npaginator = user.find_gropus\npaginator.next\n```\n\n### Categories\nThron contents are organized by categories.\n\nList existing categories (without paginator):\n```ruby\nuser.find_categories\n```\nCreate a new locale for a category:\n```ruby\nlocale = Thron::Entity::Base::new(name: 'photos', description: 'JPG and PNG images', locale: 'EN').to_payload\nuser.create_category_locale(category_id: '\u003ca_category_id\u003e', locale: locale)\n```\n\n### Disguise\nThron APIs allow to disguise another user via its apps sub-system.\n\nDisguising only works inside the block:\n```ruby\nuser.disguise(app_id: '\u003capp_id_that_can_disguise\u003e', username: '\u003cusername_to_disguise\u003e') do\n  # load the disguised user contents, each gateway will now use the disguised token id\n  contents = user.find_contents\n  # do something with contents\nend\n# finished disguising, it returns disguised token id\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcostajob%2Fthron","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcostajob%2Fthron","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcostajob%2Fthron/lists"}