toast 0.9.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +171 -86
- data/config/routes.rb +1 -27
- data/lib/generators/toast/USAGE +1 -0
- data/lib/generators/toast/templates/toast-api.rb.erb +10 -0
- data/lib/generators/toast/toast_generator.rb +9 -0
- data/lib/toast/canonical_request.rb +179 -0
- data/lib/toast/collection_request.rb +161 -0
- data/lib/toast/config_dsl/association.rb +72 -0
- data/lib/toast/config_dsl/base.rb +50 -0
- data/lib/toast/config_dsl/collection.rb +45 -0
- data/lib/toast/config_dsl/common.rb +38 -0
- data/lib/toast/config_dsl/default_handlers.rb +83 -0
- data/lib/toast/config_dsl/expose.rb +176 -0
- data/lib/toast/config_dsl/settings.rb +35 -0
- data/lib/toast/config_dsl/single.rb +15 -0
- data/lib/toast/config_dsl/via_verb.rb +49 -0
- data/lib/toast/config_dsl.rb +60 -225
- data/lib/toast/engine.rb +19 -30
- data/lib/toast/errors.rb +41 -0
- data/lib/toast/http_range.rb +17 -0
- data/lib/toast/plural_assoc_request.rb +285 -0
- data/lib/toast/rack_app.rb +133 -0
- data/lib/toast/request_helpers.rb +134 -0
- data/lib/toast/single_request.rb +66 -0
- data/lib/toast/singular_assoc_request.rb +207 -0
- data/lib/toast/version.rb +2 -2
- data/lib/toast.rb +100 -1
- metadata +83 -116
- data/app/controller/toast_controller.rb +0 -103
- data/lib/toast/active_record_extensions.rb +0 -85
- data/lib/toast/association.rb +0 -219
- data/lib/toast/collection.rb +0 -139
- data/lib/toast/record.rb +0 -123
- data/lib/toast/resource.rb +0 -175
- data/lib/toast/single.rb +0 -89
data/lib/toast/resource.rb
DELETED
@@ -1,175 +0,0 @@
|
|
1
|
-
module Toast
|
2
|
-
|
3
|
-
class ResourceNotFound < Exception; end
|
4
|
-
class MethodNotAllowed < Exception; end
|
5
|
-
class PayloadInvalid < Exception; end
|
6
|
-
class Conflict < Exception; end
|
7
|
-
class PayloadFormatError < Exception; end
|
8
|
-
class UnsupportedMediaType < Exception; end
|
9
|
-
class RequestedVersionNotDefined < Exception; end
|
10
|
-
class ResourceNotAcceptable < Exception; end
|
11
|
-
class BadRequest < Exception; end
|
12
|
-
|
13
|
-
# Represents a resource. There are following resource types as sub classes:
|
14
|
-
# Record, Collection, Association, Single
|
15
|
-
class Resource
|
16
|
-
|
17
|
-
attr_accessor :prefered_media_type, :base_uri, :payload_content_type
|
18
|
-
|
19
|
-
def initialize
|
20
|
-
raise 'ToastResource#new: use #build to create an instance'
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.build params, request
|
24
|
-
resource_name = params[:resource]
|
25
|
-
id = params[:id]
|
26
|
-
subresource_name = params[:subresource]
|
27
|
-
format = params[:format]
|
28
|
-
|
29
|
-
begin
|
30
|
-
|
31
|
-
# determine model
|
32
|
-
model = get_class_by_resource_name resource_name
|
33
|
-
|
34
|
-
# determine config for representation
|
35
|
-
# config_in: cosumed representation
|
36
|
-
# config_out: produced representation
|
37
|
-
config_out = model.toast_config request.accept_media_types.prefered
|
38
|
-
config_in = model.toast_config request.media_type
|
39
|
-
|
40
|
-
# ... or in case of an association request
|
41
|
-
config_assoc_src = model.toast_config request.headers["Assoc-source-type"] # ?
|
42
|
-
|
43
|
-
# base URI for returned object
|
44
|
-
base_uri = request.base_url + request.script_name +
|
45
|
-
(config_out.namespace ? "/" + config_out.namespace : "")
|
46
|
-
|
47
|
-
# decide which sub resource type
|
48
|
-
rsc = if id.nil? and config_out.singles.include?(subresource_name)
|
49
|
-
Toast::Single.new(model, subresource_name, params.clone, config_in, config_out)
|
50
|
-
elsif id.nil?
|
51
|
-
Toast::Collection.new(model, subresource_name, params.clone, config_in, config_out)
|
52
|
-
elsif subresource_name.nil?
|
53
|
-
Toast::Record.new(model, id, format, params.clone, config_in, config_out)
|
54
|
-
elsif (config_assoc_src && config_assoc_src.exposed_associations.include?(subresource_name))
|
55
|
-
|
56
|
-
# determine associated model
|
57
|
-
assoc_model =
|
58
|
-
model.reflect_on_all_associations.detect{|a| a.name.to_s == subresource_name}.klass
|
59
|
-
|
60
|
-
# determine config for representation of assoc. model
|
61
|
-
assoc_config_out = assoc_model.toast_config request.accept_media_types.prefered
|
62
|
-
assoc_config_in = assoc_model.toast_config request.media_type
|
63
|
-
|
64
|
-
# change base URI to associated record
|
65
|
-
base_uri = request.base_url + request.script_name +
|
66
|
-
(assoc_config_out.namespace ? "/" + assoc_config_out.namespace : "")
|
67
|
-
|
68
|
-
|
69
|
-
Toast::Association.new(model, id, subresource_name, params.clone, format, config_assoc_src,
|
70
|
-
assoc_model, assoc_config_in, assoc_config_out)
|
71
|
-
|
72
|
-
else
|
73
|
-
raise ResourceNotFound
|
74
|
-
end
|
75
|
-
|
76
|
-
# set base to be prepended to URIs
|
77
|
-
rsc.base_uri = base_uri
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
rsc
|
82
|
-
rescue NameError
|
83
|
-
raise ResourceNotFound
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.get_class_by_resource_name name
|
88
|
-
begin
|
89
|
-
model = name.singularize.classify.constantize # raises NameError
|
90
|
-
|
91
|
-
unless ((model.superclass == ActiveRecord::Base) and model.is_resourceful_model?)
|
92
|
-
raise ResourceNotFound
|
93
|
-
end
|
94
|
-
|
95
|
-
model
|
96
|
-
|
97
|
-
rescue NameError
|
98
|
-
raise ResourceNotFound
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def apply method, payload, payload_media_type, link_path_info
|
103
|
-
case method
|
104
|
-
when "PUT","POST"
|
105
|
-
if link_path_info
|
106
|
-
self.link link_path_info
|
107
|
-
else
|
108
|
-
self.send(method.downcase, payload, payload_media_type)
|
109
|
-
end
|
110
|
-
when "DELETE"
|
111
|
-
if link_path_info
|
112
|
-
self.unlink link_path_info
|
113
|
-
else
|
114
|
-
self.delete
|
115
|
-
end
|
116
|
-
when "GET"
|
117
|
-
self.get
|
118
|
-
else
|
119
|
-
raise MethodNotAllowed
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
def uri_fields record, in_collection=false
|
125
|
-
out = {}
|
126
|
-
|
127
|
-
exposed_assoc =
|
128
|
-
in_collection ? record.class.toast_config.in_collection.exposed_associations :
|
129
|
-
record.class.toast_config.exposed_associations
|
130
|
-
|
131
|
-
exposed_assoc.each do |assoc|
|
132
|
-
out[assoc] = "#{self.base_uri}#{record.uri_path}/#{assoc}"
|
133
|
-
end
|
134
|
-
|
135
|
-
out["self"] = self.base_uri + record.uri_path
|
136
|
-
|
137
|
-
out
|
138
|
-
end
|
139
|
-
|
140
|
-
|
141
|
-
def paginate_query config, relation_name, relation, params
|
142
|
-
|
143
|
-
if pagination = config.paginations[relation_name] and params[:page] =~ /\d+/
|
144
|
-
|
145
|
-
raise Toast::BadRequest.new("Page 0 not defined. Paging starts with 1") if params[:page].to_i == 0
|
146
|
-
|
147
|
-
ps = pagination[:page_size].to_i
|
148
|
-
total = relation.count
|
149
|
-
|
150
|
-
page = params[:page].to_i
|
151
|
-
total_pages = (total/ps) + (total%ps == 0 ? 0 : 1)
|
152
|
-
|
153
|
-
pagination_info = {:total => total}
|
154
|
-
|
155
|
-
if total_pages > 0
|
156
|
-
|
157
|
-
if page > total_pages
|
158
|
-
pagination_info[:prev] = total_pages
|
159
|
-
else
|
160
|
-
pagination_info[:prev] = page - 1 unless page == 1
|
161
|
-
pagination_info[:next] = page + 1 if page < total_pages
|
162
|
-
end
|
163
|
-
|
164
|
-
pagination_info[:last] = total_pages
|
165
|
-
else
|
166
|
-
pagination_info[:last] = 1
|
167
|
-
end
|
168
|
-
|
169
|
-
[relation.limit(ps).offset((page-1) * ps), pagination_info]
|
170
|
-
else
|
171
|
-
[relation, nil]
|
172
|
-
end
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
data/lib/toast/single.rb
DELETED
@@ -1,89 +0,0 @@
|
|
1
|
-
module Toast
|
2
|
-
|
3
|
-
# A Single resource is queried without an ID, by custom class methods
|
4
|
-
# or scopes of the model or ActiveRecord single finders like:
|
5
|
-
# first, last
|
6
|
-
|
7
|
-
# The single resource name must be a class method of the model and
|
8
|
-
# must return nil or an instance.
|
9
|
-
|
10
|
-
# GET is the only allowed verb. To make changes the URI with ID has
|
11
|
-
# to be used.
|
12
|
-
class Single < Resource
|
13
|
-
|
14
|
-
attr_reader :model
|
15
|
-
|
16
|
-
def initialize model, subresource_name, params, config_in, config_out
|
17
|
-
@config_in = config_in
|
18
|
-
@config_out = config_out
|
19
|
-
|
20
|
-
unless @config_out.singles.include? subresource_name
|
21
|
-
raise ResourceNotFound
|
22
|
-
end
|
23
|
-
|
24
|
-
@model = model
|
25
|
-
@params = params
|
26
|
-
@format = params[:format]
|
27
|
-
|
28
|
-
unless @model.respond_to?(subresource_name)
|
29
|
-
raise "Toast Error: Cannot find class method '#{@model}.#{subresource_name}', which is configured in 'acts_as_resource > singles'."
|
30
|
-
end
|
31
|
-
|
32
|
-
@record = if @config_out.pass_params_to.include?(subresource_name)
|
33
|
-
if @model.method(subresource_name).arity != 1
|
34
|
-
raise "Toast Error: Class method '#{@model}.#{subresource_name}' must accept one parameter, as configured by 'acts_as_resource > pass_params_to'."
|
35
|
-
end
|
36
|
-
@model.send(subresource_name, @params)
|
37
|
-
else
|
38
|
-
if(@model.method(subresource_name).arity < -1 or
|
39
|
-
@model.method(subresource_name).arity > 0)
|
40
|
-
raise "Toast Error: Class method '#{@model}.#{subresource_name}' must be callable w/o parameters"
|
41
|
-
end
|
42
|
-
@model.send(subresource_name)
|
43
|
-
end
|
44
|
-
|
45
|
-
raise ResourceNotFound if @record.nil?
|
46
|
-
end
|
47
|
-
|
48
|
-
def get
|
49
|
-
case @format
|
50
|
-
when "html"
|
51
|
-
{
|
52
|
-
:template => "resources/#{model.to_s.underscore}",
|
53
|
-
:locals => { model.to_s.pluralize.underscore.to_sym => @record }
|
54
|
-
}
|
55
|
-
when "json"
|
56
|
-
{
|
57
|
-
:json => @record.represent( @config_out.exposed_attributes,
|
58
|
-
@config_out.exposed_associations,
|
59
|
-
@base_uri,
|
60
|
-
@config_out.media_type),
|
61
|
-
:status => :ok
|
62
|
-
}
|
63
|
-
else
|
64
|
-
raise ResourceNotFound
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
|
-
def put
|
70
|
-
raise MethodNotAllowed
|
71
|
-
end
|
72
|
-
|
73
|
-
def post payload
|
74
|
-
raise MethodNotAllowed
|
75
|
-
end
|
76
|
-
|
77
|
-
def delete
|
78
|
-
raise MethodNotAllowed
|
79
|
-
end
|
80
|
-
|
81
|
-
def link l
|
82
|
-
raise MethodNotAllowed
|
83
|
-
end
|
84
|
-
|
85
|
-
def unlink l
|
86
|
-
raise MethodNotAllowed
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|