sinatra-rest-json 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: daf0fd1316a9beb76a91a4e42900046b18e45694
4
+ data.tar.gz: 7f3cacb357a23e1de9e11ab13d0087d0de1ab0f1
5
+ SHA512:
6
+ metadata.gz: d04e344828d494ab5bff1befcaec243594b5c58c30254932b5dfea154f109b8ede48d48a4343bcab467c54a5ef8764fd483b378b46d8647f825b64ca271c5321
7
+ data.tar.gz: 244e427c9b11c64ce3dde86f91f7271470ad267c95f8e252f96640a4b9b868556bb2872becdef088b1719c1e7a4e0fa8ce26a24d0e38a49419c6b667b359d2cb
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ pkg
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ # A sample Gemfile
2
+ gemspec
3
+ source "https://rubygems.org"
4
+
5
+
6
+ gem "sinatra"
7
+ gem "minitest"
8
+ gem "json"
9
+
10
+ group :test do
11
+ gem "minitest"
12
+ gem "rack-test"
13
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2014 Joshua Carver
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.
23
+
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Easy REST JSON APIs for Sinatra & Active Record
2
+
3
+
4
+ Getting started
5
+
6
+ ## 1. Setup your Gemfile
7
+
8
+ ```ruby
9
+ # Gemfile
10
+
11
+ gem "sinatra"
12
+ gem "sinatra-activerecord" # see https://github.com/janko-m/sinatra-activerecord
13
+ gem "sinatra-rest-json"
14
+ gem "json"
15
+
16
+ ```
17
+
18
+ ## 2. Setup your Sinatra App
19
+
20
+ ```ruby
21
+ require 'sinatra'
22
+ require 'sinatra/activerecord'
23
+ require 'sinatra/rest_json'
24
+ require 'json'
25
+
26
+
27
+ set :database, {adapter: "sqlite3", database: "foo.sqlite3"}
28
+
29
+
30
+ # Assume some models & database tables exit
31
+ # Make sure to provide a to_json method on them
32
+ class Product < ActiveRecord::Base
33
+ def to_json
34
+ { :name => name, :price => price }.to_json
35
+ end
36
+ end
37
+
38
+
39
+ # Set up your REST routes
40
+ rest_json Product
41
+ ```
42
+ ## 3. Profit
43
+
44
+ ### Now your app automatically has the following routes which returns JSON data from your model:
45
+
46
+ - **GET** /products (all)
47
+ - **GET** /products/:id (find)
48
+
49
+ - **POST** /products (create)
50
+ - **PUT** /products/:id (update)
51
+
52
+ - **DELETE** /people/:id (destroy)
53
+
54
+
55
+ *Note for POST/PUT operations the data parameters should be like so: { product: { name: "foo", price: 1 }}
56
+
57
+
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ end
7
+
8
+ desc "Run tests"
9
+ task :default => :test
@@ -0,0 +1,78 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module Sinatra
5
+ module REST
6
+ NOT_FOUND = { :errors => ["record doesn't exist"] }.to_json
7
+ MODEL_REGEX = /([A-Z0-9]{1}[a-z0-9]+)/
8
+
9
+ def rest_json(model_class, opts = {})
10
+ model_name = model_class.name.scan(MODEL_REGEX).join("_").downcase
11
+ route_name = model_class.table_name
12
+
13
+ # all
14
+ get "/#{route_name}" do
15
+ content_type :json
16
+ "[" + model_class.all.collect { |m| m.to_json }.join(",") + "]"
17
+ end
18
+
19
+ # find
20
+ get "/#{route_name}/:id" do
21
+ content_type :json
22
+ model = model_class.find(params[:id].to_i)
23
+
24
+ if model.nil?
25
+ NOT_FOUND
26
+ else
27
+ model.to_json
28
+ end
29
+ end
30
+
31
+ # create
32
+ post "/#{route_name}" do
33
+ content_type :json
34
+
35
+ model = model_class.new(params[model_name])
36
+
37
+ if model.save
38
+ model.to_json
39
+ else
40
+ { :errors => model.errors }.to_json
41
+ end
42
+ end
43
+
44
+ # update
45
+ put "/#{route_name}/:id" do
46
+ content_type :json
47
+
48
+ model = model_class.find(params[:id].to_i)
49
+
50
+ if model.nil?
51
+ NOT_FOUND
52
+ else
53
+ if model.update_attributes(params[model_name])
54
+ model.to_json
55
+ else
56
+ { :errors => model.errors }.to_json
57
+ end
58
+ end
59
+ end
60
+
61
+ # delete
62
+ delete "/#{route_name}/:id" do
63
+ content_type :json
64
+
65
+ model = model_class.find(params[:id].to_i)
66
+
67
+ if model.nil?
68
+ NOT_FOUND
69
+ else
70
+ model.destroy.to_json
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ register REST
78
+ end
@@ -0,0 +1,78 @@
1
+ require 'sinatra/base'
2
+ require 'json'
3
+
4
+ module Sinatra
5
+ module REST
6
+ NOT_FOUND = { :errors => ["record doesn't exist"] }.to_json
7
+ MODEL_REGEX = /([A-Z0-9]{1}[a-z0-9]+)/
8
+
9
+ def rest_json(model_class, opts = {})
10
+ model_name = model_class.name.scan(MODEL_REGEX).join("_").downcase
11
+ route_name = model_class.table_name
12
+
13
+ # all
14
+ get "/#{route_name}" do
15
+ content_type :json
16
+ "[" + model_class.all.collect { |m| m.to_json }.join(",") + "]"
17
+ end
18
+
19
+ # find
20
+ get "/#{route_name}/:id" do
21
+ content_type :json
22
+ model = model_class.find(params[:id].to_i)
23
+
24
+ if model.nil?
25
+ NOT_FOUND
26
+ else
27
+ model.to_json
28
+ end
29
+ end
30
+
31
+ # create
32
+ put "/#{route_name}" do
33
+ content_type :json
34
+
35
+ model = model_class.new(params[model_name])
36
+
37
+ if model.save
38
+ model.to_json
39
+ else
40
+ { :errors => model.errors }.to_json
41
+ end
42
+ end
43
+
44
+ # update
45
+ post "/#{route_name}/:id" do
46
+ content_type :json
47
+
48
+ model = model_class.find(params[:id].to_i)
49
+
50
+ if model.nil?
51
+ NOT_FOUND
52
+ else
53
+ if model.update_attributes(params[model_name])
54
+ model.to_json
55
+ else
56
+ { :errors => model.errors }.to_json
57
+ end
58
+ end
59
+ end
60
+
61
+ # delete
62
+ delete "/#{route_name}/:id" do
63
+ content_type :json
64
+
65
+ model = model_class.find(params[:id].to_i)
66
+
67
+ if model.nil?
68
+ NOT_FOUND
69
+ else
70
+ model.destroy.to_json
71
+ end
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ register REST
78
+ end
@@ -0,0 +1,20 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'sinatra-rest-json'
3
+ s.version = '0.1'
4
+
5
+ s.date = '2014-05-05'
6
+ s.summary = "Easy rest routes for Sinatra Applciations"
7
+ s.description = ""
8
+ s.authors = ["Joshua Carver"]
9
+ s.homepage = 'http://rubygems.org/gems/sinatra-rest-json'
10
+ s.license = 'MIT'
11
+
12
+
13
+ s.files = `git ls-files -z`.split("\x0")
14
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
15
+ s.test_files = s.files.grep(%r{^(test|s|features)/})
16
+ s.require_paths = ["lib"]
17
+
18
+ s.add_development_dependency "bundler", "~> 1.5"
19
+ s.add_development_dependency "rake"
20
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,77 @@
1
+ class FooModel
2
+
3
+ @@models = []
4
+ @@next_id = 1
5
+
6
+ attr_accessor :id, :name, :errors
7
+
8
+ class << self
9
+ def table_name
10
+ "foo_models"
11
+ end
12
+
13
+ def all
14
+ @@models
15
+ end
16
+
17
+ def destroy_all
18
+ @@models = []
19
+ @@next_id = 1
20
+ end
21
+
22
+ def find(id)
23
+ @@models.select { |m| m.id == id }.first
24
+ end
25
+
26
+ def create(params)
27
+ @@models << FooModel.new(@@next_id, params[:name])
28
+ @@next_id += 1
29
+ @@models[-1]
30
+ end
31
+ end
32
+
33
+ def initialize(*args)
34
+ if args.size == 0
35
+ @id = nil
36
+ @name = nil
37
+ elsif args.size == 2
38
+ @id = args[0].to_i
39
+ @name = args[1]
40
+ else args.size == 1
41
+ update_attributes(args[0])
42
+ end
43
+ end
44
+
45
+ def save
46
+ if @name.nil?
47
+ @errors = [
48
+ { :name => "cant be blank" }
49
+ ]
50
+
51
+ false
52
+ else
53
+ @@models << self
54
+ self.id = @@next_id
55
+ @@next_id += 1
56
+
57
+ true
58
+ end
59
+ end
60
+
61
+ def update_attributes(hash)
62
+ unless hash.empty?
63
+ @id = hash['id'].to_i if hash.include?('id')
64
+ @name = hash['name'] if hash.include?('name')
65
+ end
66
+ end
67
+
68
+ def destroy
69
+ @@models.delete(self)
70
+ self
71
+ end
72
+
73
+ def to_json
74
+ { :id => @id, :name => @name }.to_json
75
+ end
76
+ end
77
+
@@ -0,0 +1,107 @@
1
+ ENV['RACK_ENV'] = 'test'
2
+
3
+ require 'rack/test'
4
+ require "minitest/autorun"
5
+
6
+ require 'sinatra/base'
7
+ require 'sinatra/rest-json'
8
+ require 'json'
9
+
10
+ require File.join(File.dirname(__FILE__), "helper")
11
+
12
+ class TestApp < Sinatra::Base
13
+ register Sinatra::REST
14
+ rest_json FooModel
15
+ end
16
+
17
+
18
+ describe "app" do
19
+ include Rack::Test::Methods
20
+
21
+ def app
22
+ TestApp
23
+ end
24
+
25
+ before do
26
+ FooModel.destroy_all
27
+ end
28
+
29
+ describe "GET /" do
30
+ it "should be empty when no models" do
31
+ get "/foo_models"
32
+ assert_equal last_response.body, "[]"
33
+ end
34
+
35
+ it "should not be empty when models present" do
36
+ FooModel.create(:name => "foo1")
37
+
38
+ get "/foo_models"
39
+ assert_equal last_response.body, "[{\"id\":1,\"name\":\"foo1\"}]"
40
+ end
41
+ end
42
+
43
+
44
+ describe "GET /foo_models/:id" do
45
+ it "should give error when no models" do
46
+ get "/foo_models/1"
47
+ assert_equal last_response.body, "{\"errors\":[\"record doesn\'t exist\"]}"
48
+ end
49
+
50
+ it "should find model when it exists" do
51
+ model = FooModel.create(:name => "foo1")
52
+ get "/foo_models/#{model.id}"
53
+ assert_equal last_response.body, "{\"id\":#{model.id},\"name\":\"foo1\"}"
54
+ end
55
+ end
56
+
57
+ describe "POST /foo_models" do
58
+ it "should create a new model" do
59
+ assert_equal FooModel.all.size, 0
60
+ post "/foo_models", { :foo_model => { :name => "foo1" } }
61
+ assert_equal last_response.body, "{\"id\":1,\"name\":\"foo1\"}"
62
+ assert_equal FooModel.all.size, 1
63
+ end
64
+
65
+ it "should send back errors when validation fails" do
66
+ post "/foo_models", { :foo_model => { :name => nil } }
67
+ assert_equal last_response.body, "{\"errors\":[{\"name\":\"cant be blank\"}]}"
68
+ end
69
+ end
70
+
71
+
72
+ describe "PUT /foo_models/:id" do
73
+ it "should give error when not found" do
74
+ put "/foo_models/1", { :name => "boo" }
75
+ assert_equal last_response.body, "{\"errors\":[\"record doesn\'t exist\"]}"
76
+ end
77
+
78
+ it "should update model when it exists" do
79
+ FooModel.create(:name => "foo1")
80
+ put "/foo_models/1", { :foo_model => { :name => "boo" } }
81
+ assert_equal last_response.body, "{\"id\":1,\"name\":\"boo\"}"
82
+ end
83
+ end
84
+
85
+
86
+ describe "DELETE /foo_models/:id" do
87
+ it "should give error when not found" do
88
+ delete "/foo_models/1"
89
+ assert_equal last_response.body, "{\"errors\":[\"record doesn\'t exist\"]}"
90
+ end
91
+
92
+ it "should respond with delted object" do
93
+ FooModel.create(:name => "foo1")
94
+ delete "/foo_models/1"
95
+ assert_equal last_response.body, "{\"id\":1,\"name\":\"foo1\"}"
96
+ end
97
+
98
+ it "should actually delete model" do
99
+ FooModel.create(:name => "foo1")
100
+ assert_equal FooModel.all.size, 1
101
+
102
+ delete "/foo_models/1"
103
+ assert_equal FooModel.all.size, 0
104
+ end
105
+ end
106
+
107
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sinatra-rest-json
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Joshua Carver
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-05-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: ''
42
+ email:
43
+ executables: []
44
+ extensions: []
45
+ extra_rdoc_files: []
46
+ files:
47
+ - .gitignore
48
+ - Gemfile
49
+ - LICENSE
50
+ - README.md
51
+ - Rakefile
52
+ - lib/sinatra/rest-json.rb
53
+ - lib/sinatra/rest_json.rb
54
+ - sinatra-rest-json.gemspec
55
+ - test/helper.rb
56
+ - test/test_sinatra_rest_json.rb
57
+ homepage: http://rubygems.org/gems/sinatra-rest-json
58
+ licenses:
59
+ - MIT
60
+ metadata: {}
61
+ post_install_message:
62
+ rdoc_options: []
63
+ require_paths:
64
+ - lib
65
+ required_ruby_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ requirements: []
76
+ rubyforge_project:
77
+ rubygems_version: 2.2.2
78
+ signing_key:
79
+ specification_version: 4
80
+ summary: Easy rest routes for Sinatra Applciations
81
+ test_files:
82
+ - test/helper.rb
83
+ - test/test_sinatra_rest_json.rb