apicco-sdk 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +30 -0
- data/.ruby-version +1 -0
- data/Gemfile +7 -0
- data/README.md +72 -0
- data/Rakefile +10 -0
- data/apicco_sdk.gemspec +33 -0
- data/bin/console +14 -0
- data/bin/publish +4 -0
- data/bin/setup +8 -0
- data/bin/version.sh +8 -0
- data/lib/apicco_sdk.rb +5 -0
- data/lib/apicco_sdk/client.rb +83 -0
- data/lib/apicco_sdk/helpers.rb +17 -0
- data/lib/apicco_sdk/version.rb +3 -0
- metadata +184 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2f1c77ce5e818f6c2db82b6d6b43c751facb7eb2d46dd2e63a3afde6e8192af4
|
4
|
+
data.tar.gz: 0bb26bbae5c365f893116e1f404e0bac2b9427bb7ce094cbad9711c675d82046
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e76ff5a137c475e0b9b69b1a24e270f8e57c260c0de5bbb637301e796ee81a61993daabff928456dd6f7853a40775c30bf66f57a9b29ebe5bcf78cd578015078
|
7
|
+
data.tar.gz: 2abc94f83a75f48808215d3f56216c64488fb826e6879e1d72d6a7c3c02b90235064692e57f76cecf3cc210ef03001a63587532886ff49e9e6461d98a0c502ce
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- "config/**/*.rb"
|
4
|
+
|
5
|
+
Metrics/AbcSize:
|
6
|
+
Max: 40
|
7
|
+
|
8
|
+
Metrics/ClassLength:
|
9
|
+
Max: 1000
|
10
|
+
|
11
|
+
Metrics/LineLength:
|
12
|
+
Max: 160
|
13
|
+
|
14
|
+
Metrics/MethodLength:
|
15
|
+
Max: 40
|
16
|
+
|
17
|
+
Style/Documentation:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Style/NumericLiterals:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/GlobalVars:
|
24
|
+
Enabled: false
|
25
|
+
|
26
|
+
Style/DotPosition:
|
27
|
+
EnforcedStyle: trailing
|
28
|
+
|
29
|
+
Style/StringLiterals:
|
30
|
+
EnforcedStyle: double_quotes
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.6
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
# Apicco-SDK
|
2
|
+
|
3
|
+
Apicco SDK creates dynamically an [Apicco API](https://github.com/SokratisVidros/apicco/blob/master/lib/README.md) client, that works both in Node and browser environments.
|
4
|
+
|
5
|
+
Port of [JS Apicco-SDK](../js/README.md) in Ruby.
|
6
|
+
|
7
|
+
```
|
8
|
+
POST /api/movies.create api.movies_create(title: 'Foo')
|
9
|
+
POST /api/movies.info api.movies_info(movie_id: 42)
|
10
|
+
POST /api/movies.list api.movies_list
|
11
|
+
POST /api/movies.update api.movies_update(movie_id: 42, title: 'Bar')
|
12
|
+
POST /api/movies.delete api.movies_delete(movie_id: 42)
|
13
|
+
```
|
14
|
+
|
15
|
+
## Usage
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
require 'apicco-sdk'
|
19
|
+
> token = 'deadbeef'
|
20
|
+
> intercept = ->(req) { req[:headers]["Authorization"]="Bearer #{token}" }
|
21
|
+
> api = ::ApiccoSDK::Client.new('http://example.com', rel_path:'api/v2', intercept:intercept)
|
22
|
+
> api.movies_list
|
23
|
+
```
|
24
|
+
|
25
|
+
## RPC style method invocation
|
26
|
+
|
27
|
+
Apicco SDK enables developers to invoke remote endpoints in an RPC fashion. For example:
|
28
|
+
|
29
|
+
```
|
30
|
+
POST /api/users.sayHello => api.users_sayHello(name: 'John Doe')
|
31
|
+
```
|
32
|
+
|
33
|
+
## Minimal versionless clients
|
34
|
+
|
35
|
+
Apicco SDK leverages discovery endpoint and fetches latest API description upon initialization. That way, client updates are not required when the API is modified and changes are backwards compatible.
|
36
|
+
|
37
|
+
Moreover, client size is minimal since there is no static code for any of endpoint.
|
38
|
+
|
39
|
+
## Human friendly error messages
|
40
|
+
|
41
|
+
Apicco API returns JSON error objects that contain human friendly error messages. For example when `foo_id` request parameter validation fails, the following error will be returned to the client:
|
42
|
+
|
43
|
+
```json
|
44
|
+
{
|
45
|
+
"error": "Bad Request",
|
46
|
+
"message": "Invalid Request Body - child \"foo_id\" fails because [\"foo_id\" must be a number]",
|
47
|
+
"statusCode": 400
|
48
|
+
```
|
49
|
+
|
50
|
+
## Options
|
51
|
+
|
52
|
+
**origin** (Required positional argument)
|
53
|
+
|
54
|
+
Specify the origin of the Apicco API server
|
55
|
+
|
56
|
+
**rel_path**
|
57
|
+
|
58
|
+
Specify the relative of the Apicco API
|
59
|
+
|
60
|
+
_Defaults to `api/v1`_
|
61
|
+
|
62
|
+
**intercept**
|
63
|
+
|
64
|
+
Specify an interceptor lamdbda that will be executed before each request
|
65
|
+
|
66
|
+
_Defaults to `->(req) { req }`_
|
67
|
+
|
68
|
+
**api**
|
69
|
+
|
70
|
+
Specify the discovery endpoint response as hash to avoid the request
|
71
|
+
|
72
|
+
_Defaults to `{}`_
|
data/Rakefile
ADDED
data/apicco_sdk.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "apicco_sdk/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "apicco-sdk"
|
7
|
+
spec.version = ApiccoSDK::VERSION
|
8
|
+
spec.authors = ["Dimitris Klouvas"]
|
9
|
+
spec.email = ["dimitris.klouvas@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Apicco Ruby SDK"
|
12
|
+
spec.description = "Apicco Ruby SDK to export client using discovery service"
|
13
|
+
spec.homepage = "https://github.com/sokratisvidros/apicco#readme"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency "json", "~> 2.2.0"
|
24
|
+
spec.add_dependency "rest-client", "~> 2.0.2"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.0.2"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "gem-release", "~> 2.0"
|
29
|
+
spec.add_development_dependency "minitest", "~> 5.0"
|
30
|
+
spec.add_development_dependency "webmock", "~> 3.3"
|
31
|
+
spec.add_development_dependency "byebug", "~> 10.0"
|
32
|
+
spec.add_development_dependency "mocha", "~> 1.7"
|
33
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "apicco_sdk"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/publish
ADDED
data/bin/setup
ADDED
data/bin/version.sh
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
gem bump --version ${1:-'patch'} --no-commit
|
3
|
+
|
4
|
+
_package=`node -e "console.log(require('./package.json').name)"`
|
5
|
+
_version=`npm version --no-git-tag-version ${1:-'patch'}`
|
6
|
+
|
7
|
+
git commit -am "Version bump $_package@$_version"
|
8
|
+
# git tag "$_package@$_version"
|
data/lib/apicco_sdk.rb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
module ApiccoSDK
|
2
|
+
class Client
|
3
|
+
include ::ApiccoSDK::Helpers
|
4
|
+
|
5
|
+
def initialize(origin, rel_path:'api/v1', api:{}, intercept: ->(req) { req })
|
6
|
+
@rel_path = rel_path
|
7
|
+
@origin = origin
|
8
|
+
@intercept = intercept
|
9
|
+
@api = discover_api(api)
|
10
|
+
end
|
11
|
+
|
12
|
+
def method_missing(m, *args, &block)
|
13
|
+
method_name = m.to_s
|
14
|
+
super unless @api.key?(method_name)
|
15
|
+
|
16
|
+
data = (args[0] || {}).transform_keys!(&:to_s)
|
17
|
+
|
18
|
+
action, params = @api[method_name]
|
19
|
+
|
20
|
+
required_params = params.inject([]) do |memo, p|
|
21
|
+
memo << p[1..-1] if p[0] == "*"
|
22
|
+
memo
|
23
|
+
end
|
24
|
+
|
25
|
+
missing_params = required_params.select { |p| data[p].nil? }
|
26
|
+
|
27
|
+
fail "#{m} missing params: #{missing_params.join(", ")}" if missing_params.any?
|
28
|
+
request(:post, "#{@url}/#{action}", data.to_json)
|
29
|
+
end
|
30
|
+
|
31
|
+
def respond_to_missing?(method_name, include_private = false)
|
32
|
+
@api.key?(method_name) || super
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def url
|
38
|
+
@url ||= "#{@origin}/#{@rel_path}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def discover_api(api)
|
42
|
+
api = request(:get, "#{url}/discovery") if api.nil? || api.empty?
|
43
|
+
parse_api_hash(api)
|
44
|
+
end
|
45
|
+
|
46
|
+
def parse_api_hash(h)
|
47
|
+
h
|
48
|
+
.inject({}) do |memo, item|
|
49
|
+
k, v = item
|
50
|
+
new_key = underscore(k.gsub(".", "_"))
|
51
|
+
memo[new_key] = [k, v]
|
52
|
+
memo
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def request(method, url, payload = nil, headers = {})
|
57
|
+
response = _execute(method, url, payload, headers)
|
58
|
+
parse_response(response) unless response.code == 204
|
59
|
+
rescue ::RestClient::ExceptionWithResponse => e
|
60
|
+
raise e if e.http_code > 501
|
61
|
+
parse_response(e.response)
|
62
|
+
end
|
63
|
+
|
64
|
+
def parse_response(res)
|
65
|
+
JSON.parse(res)
|
66
|
+
end
|
67
|
+
|
68
|
+
def _execute(method, url, payload, headers)
|
69
|
+
req = {
|
70
|
+
method: method,
|
71
|
+
url: url,
|
72
|
+
payload: payload,
|
73
|
+
content_type: :json,
|
74
|
+
headers: {
|
75
|
+
Accept: "application/json",
|
76
|
+
"User-Agent" => "Apicco Ruby SDK #{VERSION}"
|
77
|
+
}.merge(headers)
|
78
|
+
}
|
79
|
+
@intercept.call(req)
|
80
|
+
::RestClient::Request.execute(req)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module ApiccoSDK
|
2
|
+
module Helpers
|
3
|
+
ACRONYM_REGEX = /(?=a)b/
|
4
|
+
ACRONYMS_UNDERSCORE_REGEX = /(?:(?<=([A-Za-z\d]))|\b)(#{ACRONYM_REGEX})(?=\b|[^a-z])/
|
5
|
+
# see: https://github.com/rails/rails/blob/76ae3dbed301d7178c221b0c957c6b73464eec58/activesupport/lib/active_support/inflector/methods.rb#L92
|
6
|
+
def underscore(camel_cased_word)
|
7
|
+
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
|
8
|
+
word = camel_cased_word.to_s.gsub("::", "/")
|
9
|
+
word.gsub!(ACRONYMS_UNDERSCORE_REGEX) { "#{$1 && '_' }#{$2.downcase}" }
|
10
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
11
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
12
|
+
word.tr!("-", "_")
|
13
|
+
word.downcase!
|
14
|
+
word
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: apicco-sdk
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dimitris Klouvas
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rest-client
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.0.2
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 2.0.2
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 2.0.2
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.0.2
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: gem-release
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: minitest
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '5.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '3.3'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '3.3'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: byebug
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - "~>"
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '10.0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - "~>"
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '10.0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: mocha
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.7'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.7'
|
139
|
+
description: Apicco Ruby SDK to export client using discovery service
|
140
|
+
email:
|
141
|
+
- dimitris.klouvas@gmail.com
|
142
|
+
executables: []
|
143
|
+
extensions: []
|
144
|
+
extra_rdoc_files: []
|
145
|
+
files:
|
146
|
+
- ".gitignore"
|
147
|
+
- ".rubocop.yml"
|
148
|
+
- ".ruby-version"
|
149
|
+
- Gemfile
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- apicco_sdk.gemspec
|
153
|
+
- bin/console
|
154
|
+
- bin/publish
|
155
|
+
- bin/setup
|
156
|
+
- bin/version.sh
|
157
|
+
- lib/apicco_sdk.rb
|
158
|
+
- lib/apicco_sdk/client.rb
|
159
|
+
- lib/apicco_sdk/helpers.rb
|
160
|
+
- lib/apicco_sdk/version.rb
|
161
|
+
homepage: https://github.com/sokratisvidros/apicco#readme
|
162
|
+
licenses:
|
163
|
+
- MIT
|
164
|
+
metadata: {}
|
165
|
+
post_install_message:
|
166
|
+
rdoc_options: []
|
167
|
+
require_paths:
|
168
|
+
- lib
|
169
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
175
|
+
requirements:
|
176
|
+
- - ">="
|
177
|
+
- !ruby/object:Gem::Version
|
178
|
+
version: '0'
|
179
|
+
requirements: []
|
180
|
+
rubygems_version: 3.0.3
|
181
|
+
signing_key:
|
182
|
+
specification_version: 4
|
183
|
+
summary: Apicco Ruby SDK
|
184
|
+
test_files: []
|