dato 0.5.1 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +0 -38
- data/lib/dato/account/client.rb +3 -70
- data/lib/dato/api_client.rb +98 -0
- data/lib/dato/json_api_serializer.rb +72 -17
- data/lib/dato/paginator.rb +33 -0
- data/lib/dato/repo.rb +91 -0
- data/lib/dato/site/client.rb +3 -91
- data/lib/dato/upload/file.rb +1 -1
- data/lib/dato/version.rb +1 -1
- metadata +5 -20
- data/lib/dato/account/repo/account.rb +0 -23
- data/lib/dato/account/repo/base.rb +0 -27
- data/lib/dato/account/repo/deploy_event.rb +0 -18
- data/lib/dato/account/repo/site.rb +0 -49
- data/lib/dato/site/paginator.rb +0 -35
- data/lib/dato/site/repo/access_token.rb +0 -47
- data/lib/dato/site/repo/base.rb +0 -27
- data/lib/dato/site/repo/deploy_event.rb +0 -18
- data/lib/dato/site/repo/field.rb +0 -41
- data/lib/dato/site/repo/item.rb +0 -80
- data/lib/dato/site/repo/item_type.rb +0 -50
- data/lib/dato/site/repo/menu_item.rb +0 -44
- data/lib/dato/site/repo/role.rb +0 -42
- data/lib/dato/site/repo/search_result.rb +0 -14
- data/lib/dato/site/repo/site.rb +0 -23
- data/lib/dato/site/repo/upload.rb +0 -59
- data/lib/dato/site/repo/upload_request.rb +0 -19
- data/lib/dato/site/repo/user.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7107aad93e6809c4140c2167e1d5ce2cc446c45bf05e66521916a357a52f2b2a
|
4
|
+
data.tar.gz: a3f336225fa11c3d721b07171b432201326b03e58fb394ec0f26911c5320f8e9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df93d0a0883dd2a6d728cb5f8ceb7e4b6c46f9063a75bc79ecf1442458f67f5a32aa0a95f7be9a9fc89360b02636206c1bf4bcc6f7689847eb2d2c7e9a269969
|
7
|
+
data.tar.gz: 4a733da2b3626f47018fc6fadefb96d50ffd4959b871f952c78c382225504faa6d894d4aaaed68ba458d91fa6e138fe18ec2e28d550d840a2771c6e823cf48a4
|
data/Rakefile
CHANGED
@@ -1,44 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
require 'bundler/gem_tasks'
|
3
3
|
require 'rspec/core/rake_task'
|
4
|
-
require 'open-uri'
|
5
|
-
|
6
|
-
require_relative './build/build_client'
|
7
4
|
|
8
5
|
RSpec::Core::RakeTask.new(:spec)
|
9
|
-
|
10
6
|
task default: :spec
|
11
|
-
|
12
|
-
desc 'Regenerates the client starting from the JSON Hyperschema'
|
13
|
-
task :regenerate do
|
14
|
-
BuildClient.new(
|
15
|
-
open('https://site-api.datocms.com/docs/site-api-hyperschema.json').read,
|
16
|
-
'site',
|
17
|
-
%w(session item upload user#update)
|
18
|
-
).build
|
19
|
-
|
20
|
-
BuildClient.new(
|
21
|
-
open('https://site-api.datocms.com/docs/account-api-hyperschema.json').read,
|
22
|
-
'account',
|
23
|
-
%w(
|
24
|
-
session
|
25
|
-
account#create account#reset_password
|
26
|
-
subscription
|
27
|
-
portal_session
|
28
|
-
)
|
29
|
-
).build
|
30
|
-
end
|
31
|
-
|
32
|
-
desc 'Open an irb (or pry) session preloaded with this gem'
|
33
|
-
task :console do
|
34
|
-
begin
|
35
|
-
require 'pry'
|
36
|
-
gem_name = File.basename(Dir.pwd)
|
37
|
-
sh %(pry -I lib -r #{gem_name}.rb)
|
38
|
-
rescue LoadError => _
|
39
|
-
sh %(irb -rubygems -I lib -r #{gem_name}.rb)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
require 'rubocop/rake_task'
|
44
|
-
RuboCop::RakeTask.new
|
data/lib/dato/account/client.rb
CHANGED
@@ -1,79 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
require '
|
3
|
-
require 'faraday_middleware'
|
4
|
-
require 'json'
|
5
|
-
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
-
|
7
|
-
require 'dato/version'
|
8
|
-
|
9
|
-
require 'dato/account/repo/account'
|
10
|
-
require 'dato/account/repo/site'
|
11
|
-
require 'dato/account/repo/deploy_event'
|
12
|
-
require 'dato/api_error'
|
13
|
-
|
14
|
-
require 'cacert'
|
2
|
+
require 'dato/api_client'
|
15
3
|
|
16
4
|
module Dato
|
17
5
|
module Account
|
18
6
|
class Client
|
19
|
-
|
20
|
-
account: Repo::Account,
|
21
|
-
sites: Repo::Site,
|
22
|
-
deploy_events: Repo::DeployEvent
|
23
|
-
}.freeze
|
24
|
-
|
25
|
-
attr_reader :token, :base_url, :schema, :extra_headers
|
26
|
-
|
27
|
-
def initialize(token, options = {})
|
28
|
-
@token = token
|
29
|
-
@base_url = options[:base_url] || 'https://account-api.datocms.com'
|
30
|
-
@extra_headers = options[:extra_headers] || {}
|
31
|
-
end
|
32
|
-
|
33
|
-
REPOS.each do |method_name, repo_klass|
|
34
|
-
define_method method_name do
|
35
|
-
instance_variable_set(
|
36
|
-
"@#{method_name}",
|
37
|
-
instance_variable_get("@#{method_name}") ||
|
38
|
-
repo_klass.new(self)
|
39
|
-
)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def request(*args)
|
44
|
-
connection.send(*args).body.with_indifferent_access
|
45
|
-
rescue Faraday::SSLError => e
|
46
|
-
raise e if ENV['SSL_CERT_FILE'] == Cacert.pem
|
47
|
-
|
48
|
-
Cacert.set_in_env
|
49
|
-
request(*args)
|
50
|
-
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
51
|
-
raise e
|
52
|
-
rescue Faraday::ClientError => e
|
53
|
-
raise ApiError, e
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def connection
|
59
|
-
options = {
|
60
|
-
url: base_url,
|
61
|
-
headers: extra_headers.merge(
|
62
|
-
'Accept' => 'application/json',
|
63
|
-
'Content-Type' => 'application/json',
|
64
|
-
'Authorization' => "Bearer #{@token}",
|
65
|
-
'User-Agent' => "ruby-client v#{Dato::VERSION}"
|
66
|
-
)
|
67
|
-
}
|
7
|
+
include ApiClient
|
68
8
|
|
69
|
-
|
70
|
-
c.request :json
|
71
|
-
c.response :json, content_type: /\bjson$/
|
72
|
-
c.response :raise_error
|
73
|
-
c.use FaradayMiddleware::FollowRedirects
|
74
|
-
c.adapter :net_http
|
75
|
-
end
|
76
|
-
end
|
9
|
+
json_schema 'account-api'
|
77
10
|
end
|
78
11
|
end
|
79
12
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
require 'json_schema'
|
5
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
6
|
+
require 'active_support/inflector'
|
7
|
+
|
8
|
+
require 'dato/version'
|
9
|
+
require 'dato/repo'
|
10
|
+
|
11
|
+
require 'dato/api_error'
|
12
|
+
|
13
|
+
require 'cacert'
|
14
|
+
|
15
|
+
module Dato
|
16
|
+
module ApiClient
|
17
|
+
def self.included(base)
|
18
|
+
base.extend ClassMethods
|
19
|
+
|
20
|
+
base.class_eval do
|
21
|
+
attr_reader :token, :base_url, :schema, :extra_headers
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def json_schema(subdomain)
|
27
|
+
define_method(:initialize) do |token, options = {}|
|
28
|
+
@token = token
|
29
|
+
@base_url = options[:base_url] || "https://#{subdomain}.datocms.com"
|
30
|
+
@extra_headers = options[:extra_headers] || {}
|
31
|
+
end
|
32
|
+
|
33
|
+
url = URI.parse("https://#{subdomain}.datocms.com/docs/#{subdomain}-hyperschema.json")
|
34
|
+
response = Net::HTTP.get(url)
|
35
|
+
|
36
|
+
schema = JsonSchema.parse!(JSON.parse(response))
|
37
|
+
schema.expand_references!
|
38
|
+
|
39
|
+
schema.definitions.each do |type, schema|
|
40
|
+
is_collection = schema.links.select{|x| x.rel === "instances"}.any?
|
41
|
+
|
42
|
+
if is_collection
|
43
|
+
type = type.pluralize
|
44
|
+
end
|
45
|
+
|
46
|
+
define_method(type) do
|
47
|
+
instance_variable_set(
|
48
|
+
"@#{type}",
|
49
|
+
instance_variable_get("@#{type}") ||
|
50
|
+
Dato::Repo.new(self, type, schema)
|
51
|
+
)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def request(*args)
|
58
|
+
connection.send(*args).body.with_indifferent_access
|
59
|
+
rescue Faraday::SSLError => e
|
60
|
+
raise e if ENV['SSL_CERT_FILE'] == Cacert.pem
|
61
|
+
|
62
|
+
Cacert.set_in_env
|
63
|
+
request(*args)
|
64
|
+
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
|
65
|
+
puts e.message
|
66
|
+
raise e
|
67
|
+
rescue Faraday::ClientError => e
|
68
|
+
error = ApiError.new(e)
|
69
|
+
puts '===='
|
70
|
+
puts error.message
|
71
|
+
puts '===='
|
72
|
+
raise error
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def connection
|
78
|
+
options = {
|
79
|
+
url: base_url,
|
80
|
+
headers: extra_headers.merge(
|
81
|
+
'Accept' => 'application/json',
|
82
|
+
'Content-Type' => 'application/json',
|
83
|
+
'Authorization' => "Bearer #{@token}",
|
84
|
+
'User-Agent' => "ruby-client v#{Dato::VERSION}",
|
85
|
+
'X-Api-Version' => "2"
|
86
|
+
)
|
87
|
+
}
|
88
|
+
|
89
|
+
@connection ||= Faraday.new(options) do |c|
|
90
|
+
c.request :json
|
91
|
+
c.response :json, content_type: /\bjson$/
|
92
|
+
c.response :raise_error
|
93
|
+
c.use FaradayMiddleware::FollowRedirects
|
94
|
+
c.adapter :net_http
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -1,21 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
module Dato
|
3
3
|
class JsonApiSerializer
|
4
|
-
attr_reader :
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
type:,
|
9
|
-
attributes: [],
|
10
|
-
required_attributes: [],
|
11
|
-
relationships: {},
|
12
|
-
required_relationships: []
|
13
|
-
)
|
4
|
+
attr_reader :link, :type
|
5
|
+
|
6
|
+
def initialize(type, link)
|
7
|
+
@link = link
|
14
8
|
@type = type
|
15
|
-
@attributes = attributes
|
16
|
-
@required_attributes = required_attributes
|
17
|
-
@relationships = relationships
|
18
|
-
@required_relationships = required_relationships
|
19
9
|
end
|
20
10
|
|
21
11
|
def serialize(resource, id = nil)
|
@@ -37,7 +27,7 @@ module Dato
|
|
37
27
|
def serialized_attributes(resource)
|
38
28
|
result = {}
|
39
29
|
|
40
|
-
attributes.each do |attribute|
|
30
|
+
attributes(resource).each do |attribute|
|
41
31
|
if resource.key? attribute
|
42
32
|
result[attribute] = resource[attribute]
|
43
33
|
elsif required_attributes.include? attribute
|
@@ -54,7 +44,6 @@ module Dato
|
|
54
44
|
relationships.each do |relationship, meta|
|
55
45
|
if resource.key? relationship
|
56
46
|
value = resource[relationship]
|
57
|
-
|
58
47
|
data = if value
|
59
48
|
if meta[:collection]
|
60
49
|
value.map do |id|
|
@@ -66,12 +55,78 @@ module Dato
|
|
66
55
|
end
|
67
56
|
result[relationship] = { data: data }
|
68
57
|
|
69
|
-
elsif required_relationships.include?
|
58
|
+
elsif required_relationships.include?(relationship)
|
70
59
|
throw "Required attribute: #{relationship}"
|
71
60
|
end
|
72
61
|
end
|
73
62
|
|
74
63
|
result
|
75
64
|
end
|
65
|
+
|
66
|
+
def attributes(resource)
|
67
|
+
if type == "item"
|
68
|
+
resource.keys - [:item_type, :id]
|
69
|
+
end
|
70
|
+
|
71
|
+
link_attributes["properties"].keys.map(&:to_sym)
|
72
|
+
end
|
73
|
+
|
74
|
+
def required_attributes
|
75
|
+
if type == "item"
|
76
|
+
[]
|
77
|
+
end
|
78
|
+
|
79
|
+
(link_attributes.required || []).map(&:to_sym)
|
80
|
+
end
|
81
|
+
|
82
|
+
def relationships
|
83
|
+
if type == "item"
|
84
|
+
{
|
85
|
+
item_type: { collection: false, type: 'item_type' }
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
if !link_relationships
|
90
|
+
return {}
|
91
|
+
end
|
92
|
+
|
93
|
+
link_relationships.properties.reduce({}) do |acc, (relationship, schema)|
|
94
|
+
is_collection = schema.properties["data"].type.first == 'array'
|
95
|
+
|
96
|
+
definition = if is_collection
|
97
|
+
schema.properties['data'].items
|
98
|
+
elsif schema.properties['data'].type.first == 'object'
|
99
|
+
schema.properties['data']
|
100
|
+
else
|
101
|
+
schema.properties['data'].any_of.find do |option|
|
102
|
+
option.type.first == 'object'
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
type = definition.properties['type']
|
107
|
+
.pattern.source.gsub(/(^\^|\$$)/, '')
|
108
|
+
|
109
|
+
acc[relationship.to_sym] = {
|
110
|
+
collection: is_collection,
|
111
|
+
type: type,
|
112
|
+
}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def required_relationships
|
117
|
+
if type == "item"
|
118
|
+
%i(item_type)
|
119
|
+
end
|
120
|
+
|
121
|
+
(link_relationships.required || []).map(&:to_sym)
|
122
|
+
end
|
123
|
+
|
124
|
+
def link_attributes
|
125
|
+
link.schema.properties["data"].properties["attributes"]
|
126
|
+
end
|
127
|
+
|
128
|
+
def link_relationships
|
129
|
+
link.schema.properties["data"].properties["relationships"]
|
130
|
+
end
|
76
131
|
end
|
77
132
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Dato
|
2
|
+
class Paginator
|
3
|
+
def initialize(client, base_endpoint, filters)
|
4
|
+
@client, @base_endpoint, @filters = client, base_endpoint, filters
|
5
|
+
end
|
6
|
+
|
7
|
+
def response
|
8
|
+
items_per_page = 100
|
9
|
+
|
10
|
+
base_response = @client.request(
|
11
|
+
:get, @base_endpoint, @filters.dup.merge('page[limit]' => items_per_page)
|
12
|
+
)
|
13
|
+
|
14
|
+
extra_pages = (
|
15
|
+
base_response[:meta][:total_count] / items_per_page.to_f
|
16
|
+
).ceil - 1
|
17
|
+
|
18
|
+
extra_pages.times do |page|
|
19
|
+
base_response[:data] += @client.request(
|
20
|
+
:get,
|
21
|
+
@base_endpoint,
|
22
|
+
@filters.dup.merge(
|
23
|
+
'page[offset]' => items_per_page * (page + 1),
|
24
|
+
'page[limit]' => items_per_page
|
25
|
+
)
|
26
|
+
)[:data]
|
27
|
+
end
|
28
|
+
|
29
|
+
base_response
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
data/lib/dato/repo.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require 'dato/json_api_serializer'
|
3
|
+
require 'dato/json_api_deserializer'
|
4
|
+
require 'dato/paginator'
|
5
|
+
|
6
|
+
module Dato
|
7
|
+
class Repo
|
8
|
+
attr_reader :client, :type, :schema
|
9
|
+
|
10
|
+
IDENTITY_REGEXP = /\{\(.*?definitions%2F(.*?)%2Fdefinitions%2Fidentity\)}/
|
11
|
+
|
12
|
+
METHOD_NAMES = {
|
13
|
+
"instances" => :all,
|
14
|
+
"self" => :find,
|
15
|
+
}
|
16
|
+
|
17
|
+
def initialize(client, type, schema)
|
18
|
+
@client = client
|
19
|
+
@type = type
|
20
|
+
@schema = schema
|
21
|
+
|
22
|
+
schema.links.each do |link|
|
23
|
+
method_name = METHOD_NAMES.fetch(link.rel, link.rel)
|
24
|
+
|
25
|
+
self.define_singleton_method(method_name) do |*args|
|
26
|
+
min_arguments_count = [
|
27
|
+
link.href.scan(IDENTITY_REGEXP).size,
|
28
|
+
link.schema && link.method != :get ? 1 : 0
|
29
|
+
].sum
|
30
|
+
|
31
|
+
args.size >= min_arguments_count or
|
32
|
+
raise ArgumentError.new(
|
33
|
+
"wrong number of arguments (given #{args.size}, expected #{min_arguments_count})"
|
34
|
+
)
|
35
|
+
|
36
|
+
last_url_id = nil
|
37
|
+
|
38
|
+
url = link["href"].gsub(IDENTITY_REGEXP) do |_stuff|
|
39
|
+
last_url_id = args.shift.to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
response = if %i(post put).include?(link.method)
|
43
|
+
body = if link.schema
|
44
|
+
unserialized_body = args.shift
|
45
|
+
|
46
|
+
JsonApiSerializer.new(type, link).serialize(
|
47
|
+
unserialized_body,
|
48
|
+
last_url_id
|
49
|
+
)
|
50
|
+
else
|
51
|
+
{}
|
52
|
+
end
|
53
|
+
|
54
|
+
client.request(link.method, url, body)
|
55
|
+
|
56
|
+
elsif link.method == :delete
|
57
|
+
client.request(:delete, url)
|
58
|
+
|
59
|
+
elsif link.method == :get
|
60
|
+
query_string = args.shift
|
61
|
+
|
62
|
+
all_pages = (args[0] || {}).
|
63
|
+
symbolize_keys.
|
64
|
+
fetch(:all_pages, false)
|
65
|
+
|
66
|
+
is_paginated_endpoint = link.schema &&
|
67
|
+
link.schema.properties.has_key?("page[limit]")
|
68
|
+
|
69
|
+
if is_paginated_endpoint && all_pages
|
70
|
+
Paginator.new(client, url, query_string).response
|
71
|
+
else
|
72
|
+
client.request(:get, url, query_string)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
options = if args.any?
|
77
|
+
args.shift.symbolize_keys
|
78
|
+
else
|
79
|
+
{}
|
80
|
+
end
|
81
|
+
|
82
|
+
if options.fetch(:deserialize_response, true)
|
83
|
+
JsonApiDeserializer.new.deserialize(response)
|
84
|
+
else
|
85
|
+
response
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|