wcc-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bf529343f824edee3f097074da1f2c4595413736
4
+ data.tar.gz: 6ed98c0a62c3cd6b2f98f010a7d33b986584f24d
5
+ SHA512:
6
+ metadata.gz: 46cc3b76fd6ef377a9875129ed64f99d7c3d3267b479067c57d7fb0aa95781173f2dd682bc57c8306430289e09fa77c1c81a0ce627370b040fe2d1582b4e42a6
7
+ data.tar.gz: de4678bb7d9236d184bfaa4e18c6c773de2e243cc627698bae7eecac9673584b432c47316646ee616be5162907670b43af900a14dab23cfe33153a207e0b47fd
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in wcc-api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Travis Petticrew
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # WCC::API
2
+
3
+ This library holds common code used in our applications that host APIs.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'wcc-api'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install wcc-api
20
+
21
+ ## Usage
22
+
23
+ ### `WCC::API::BaseQuery`
24
+
25
+ This provides an abstraction for building queries within an API for an
26
+ ActiveRecord backed model. You must override the `default_scope` method
27
+ to return a scope for the model you are querying on. The query object
28
+ has the following:
29
+
30
+ * `call` - calls each of the subsequent methods in order
31
+ * `paged` - adds the paging elements to the query (e.g. limit and
32
+ offset)
33
+ * `ordered` - hook to add ordering (default does nothing)
34
+ * `filtered` - hook to add filtering (default does nothing)
35
+
36
+ The Base implementation mostly just handles the paging and provides
37
+ hooks to do other useful things. Here is an example implementation of a
38
+ query object for a generic Tag model.
39
+
40
+ ```ruby
41
+ class TagQuery < WCC::API::BaseQuery
42
+ def default_scope
43
+ Tag.all
44
+ end
45
+
46
+ def ordered(scope=self.scope)
47
+ scope.ordered
48
+ end
49
+
50
+ def filtered(scope=self.scope)
51
+ Array(filter[:name_like]).each do |query|
52
+ scope = scope.name_like(query)
53
+ end
54
+ scope
55
+ end
56
+ end
57
+ ```
58
+
59
+ ### Pagination template
60
+
61
+ To use the common pagination object template include the view helper in
62
+ the controllers that will need it:
63
+
64
+ ```ruby
65
+ class APIController < ApplicationController
66
+ helper WCC::API::ViewHelpers
67
+ end
68
+ ```
69
+
70
+ Now within your jbuilder templates you can do the following to include a
71
+ Pagination object:
72
+
73
+ ```ruby
74
+ json.pagination api_pagination_for(query: @query)
75
+ ```
76
+
77
+ Where `@query` conforms to the interface specified by
78
+ `WCC::API::BaseQuery`.
79
+
80
+ ## Contributing
81
+
82
+ 1. Fork it ( https://github.com/[my-github-username]/wcc-api/fork )
83
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
84
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
85
+ 4. Push to the branch (`git push origin my-new-feature`)
86
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+
@@ -0,0 +1,83 @@
1
+ module WCC::API
2
+ class BaseQuery
3
+ attr_reader :scope
4
+ attr_accessor :limit, :offset
5
+ attr_accessor :filter
6
+
7
+ MAX_LIMIT = 50
8
+
9
+ def default
10
+ {
11
+ limit: 20,
12
+ offset: 0,
13
+ filter: {}
14
+ }
15
+ end
16
+
17
+ def permitted_keys
18
+ %i(limit offset filter)
19
+ end
20
+
21
+ def default_scope
22
+ raise NotImplementedError
23
+ end
24
+
25
+ def initialize(params, scope: default_scope)
26
+ @scope = scope
27
+ set_defaults
28
+ permitted_keys.each do |key|
29
+ self.public_send("#{key}=", params[key]) if params.has_key?(key)
30
+ end
31
+ end
32
+
33
+ def call(scope=self.scope)
34
+ scope = scope.dup
35
+ scope = paged(scope)
36
+ scope = ordered(scope)
37
+ scope = filtered(scope)
38
+ scope
39
+ end
40
+
41
+ def paged(scope=self.scope)
42
+ scope
43
+ .limit(limit)
44
+ .offset(offset)
45
+ end
46
+
47
+ def ordered(scope=self.scope)
48
+ scope
49
+ end
50
+
51
+ def filtered(scope=self.scope)
52
+ scope
53
+ end
54
+
55
+ def set_defaults
56
+ default.each do |key, value|
57
+ public_send("#{key}=", value)
58
+ end
59
+ end
60
+
61
+ def limit=(new_limit)
62
+ new_limit = new_limit.to_i
63
+ @limit = (new_limit > MAX_LIMIT) ? MAX_LIMIT : new_limit
64
+ end
65
+
66
+ def offset=(new_offset)
67
+ @offset = new_offset.to_i
68
+ end
69
+
70
+ def total
71
+ @total ||= filtered.count
72
+ end
73
+
74
+ def size
75
+ if total - offset < limit
76
+ total - offset
77
+ else
78
+ limit
79
+ end
80
+ end
81
+ end
82
+ end
83
+
@@ -0,0 +1,53 @@
1
+ module WCC::API::JSON
2
+ class Pagination
3
+ attr_reader :query, :url_for
4
+
5
+ def initialize(query, url_for:)
6
+ @query = query
7
+ @url_for = url_for
8
+ end
9
+
10
+ def to_builder
11
+ Jbuilder.new do |json|
12
+ json.total query.total
13
+ json.size query.size
14
+ json.limit query.limit
15
+ json.offset query.offset
16
+ json.order_by query.order_by if query.respond_to?(:order_by)
17
+ json.sort query.sort if query.respond_to?(:sort)
18
+ json.filter query.filter
19
+ json._links do
20
+ json.self url_for.(base_url_params)
21
+ if has_previous_page?
22
+ json.previous url_for.(base_url_params.merge(offset: query.offset - query.limit))
23
+ end
24
+ if has_next_page?
25
+ json.next url_for.(base_url_params.merge(offset: query.offset + query.limit))
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def has_previous_page?
34
+ query.offset - query.limit >= 0
35
+ end
36
+
37
+ def has_next_page?
38
+ query.offset + query.limit < query.total
39
+ end
40
+
41
+ def base_url_params
42
+ @base_url_params ||= {
43
+ limit: query.limit,
44
+ offset: query.offset,
45
+ filter: query.filter,
46
+ only_path: false
47
+ }.tap do |params|
48
+ params[:order_by] = query.order_by if query.respond_to?(:order_by)
49
+ params[:sort] = query.sort if query.respond_to?(:sort)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ module WCC::API
2
+ module JSON
3
+ end
4
+ end
5
+
6
+ require 'wcc/api/json/pagination'
@@ -0,0 +1,13 @@
1
+ require 'wcc/api'
2
+
3
+ module WCC
4
+ module API
5
+ class Railtie < Rails::Railtie
6
+ initializer 'wcc.api railtie initializer', group: :all do |app|
7
+ ActiveSupport::Inflector.inflections(:en) do |inflect|
8
+ inflect.acronym 'API'
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ RSpec.shared_examples_for :linked_pagination_object do |url_method, base_options, total|
2
+ it "includes link to current page" do
3
+ url = public_send(
4
+ url_method,
5
+ base_options.merge(limit: 2, offset: 2)
6
+ )
7
+ get url
8
+ expect(subject['_links']).to be_a(Hash)
9
+ expect(subject['_links']['self']).to eq(url)
10
+ end
11
+
12
+ it "includes link to next page when there is a next page" do
13
+ get public_send(url_method, limit: 2)
14
+ url = public_send(url_method,
15
+ base_options.merge(limit: 2, offset: 2)
16
+ )
17
+ expect(subject['_links']['next']).to eq(url)
18
+ end
19
+
20
+ it "does not include link to next page when this is the last page" do
21
+ get public_send(url_method, limit: 2, offset: total - 1)
22
+ expect(subject['_links']['next']).to be_nil
23
+ end
24
+
25
+ it "includes link to previous page when there is a previous page" do
26
+ get public_send(url_method, limit: 2, offset: 2)
27
+ url = public_send(
28
+ url_method,
29
+ base_options.merge(limit: 2, offset: 0)
30
+ )
31
+ expect(subject['_links']['previous']).to eq(url)
32
+ end
33
+
34
+ it "does not include link to next page when this is the last page" do
35
+ get public_send(url_method, limit: 2)
36
+ expect(subject['_links']['previous']).to be_nil
37
+ end
38
+ end
39
+
@@ -0,0 +1,5 @@
1
+ module WCC
2
+ module API
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,12 @@
1
+ module WCC::API
2
+ module ViewHelpers
3
+
4
+ def api_pagination_for(query:)
5
+ WCC::API::JSON::Pagination.new(
6
+ query,
7
+ url_for: -> (params) { url_for(params) }
8
+ ).to_builder
9
+ end
10
+
11
+ end
12
+ end
data/lib/wcc/api.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'wcc'
2
+ require 'wcc/api/version'
3
+
4
+ module WCC
5
+ module API
6
+ PROJECT_ROOT = File.expand_path(File.join(__FILE__, '..', '..', '..'))
7
+ end
8
+ end
9
+
10
+ if defined?(Rails)
11
+ require 'wcc/api/railtie'
12
+ end
13
+
14
+ require 'wcc/api/base_query'
15
+ require 'wcc/api/json'
16
+ require 'wcc/api/view_helpers'
17
+
data/wcc-api.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'wcc/api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "wcc-api"
8
+ spec.version = WCC::API::VERSION
9
+ spec.authors = ["Watermark Dev Team"]
10
+ spec.email = ["dev@watermark.org"]
11
+ spec.summary = %q{Holds common code used in our applications that host APIs.}
12
+ spec.description = %q{holds common code used in our applications that host APIs.}
13
+ spec.homepage = "https://github.com/watermarkchurch/wcc-api"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "wcc-base"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.6"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: wcc-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Watermark Dev Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: wcc-base
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.6'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.6'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ description: holds common code used in our applications that host APIs.
56
+ email:
57
+ - dev@watermark.org
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE.txt
65
+ - README.md
66
+ - Rakefile
67
+ - lib/wcc/api.rb
68
+ - lib/wcc/api/base_query.rb
69
+ - lib/wcc/api/json.rb
70
+ - lib/wcc/api/json/pagination.rb
71
+ - lib/wcc/api/railtie.rb
72
+ - lib/wcc/api/rspec/pagination_examples.rb
73
+ - lib/wcc/api/version.rb
74
+ - lib/wcc/api/view_helpers.rb
75
+ - wcc-api.gemspec
76
+ homepage: https://github.com/watermarkchurch/wcc-api
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.4.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: Holds common code used in our applications that host APIs.
100
+ test_files: []