fake_api 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 291b0a2acbe638fd0298f165f52361d40ed135aaae8ac5788879071810796573
4
+ data.tar.gz: ffd968738a8652262fbeeabc9ffda18c99139989a55ac22f4c7cdb0bdd7db564
5
+ SHA512:
6
+ metadata.gz: 32d03d9f654d063f9726cc944ebc4c380e0ddfca498a49a27a295f547c829cb6adfecd6ef92618021f53753dc3e85ba8b947bb31f6eb46a5ad27a52412e622bd
7
+ data.tar.gz: c2cac52ff859c0566d60d80ab448d528da024c06801f334dbb152bd225b78a962e731e45e7bb32ac6a4dc01ee19dd531ff5d9bef46008cc4ae9757bcd7573589
@@ -0,0 +1,20 @@
1
+ Copyright 2020 Igor Kasyanchuk
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,122 @@
1
+ # Fake API
2
+
3
+ The **fastest** way to prototype API with most real dummy data, and provide them to other team members.
4
+
5
+ Instead of creating many new controllers and actions, and sending random data like `"First name #{rand(100)}"` you'll get real data for developing/testing.
6
+
7
+ Gem has a syntax similar to rails routes, factory bot, and uses faker to generate dummy data.
8
+
9
+ ![Demo](/docs/fake_api_demo.gif)
10
+
11
+ Features:
12
+
13
+ * fast API prototyping
14
+ * clear and familiar syntax
15
+ * Faker for test data generation
16
+ * including links to images if needed
17
+ * manage cookies, session, headers with fake response
18
+ * executes your factories in real-time, so you always get fresh and random data
19
+ * has generator
20
+
21
+ ## Installation & Usage
22
+
23
+ Installation process is very simple.
24
+
25
+ - add `gem 'fake_api'` to the Gemfile
26
+ - run `bundle install`
27
+ - mount gem in routes.rb `mount FakeApi::Engine => '/api'`
28
+ - `rails g fake_api Product`. It will generate factory and routing files.
29
+ - edit `app/fake_api/*.rb`, define your routing and factories.
30
+ - open `localhost:300/api/projects.json` (see step 5) or `localhost:300/api/projects.xml` (to return XML in API response)
31
+ - profit :)
32
+
33
+ You can keep your routing and factories in many files.
34
+
35
+ ## Examples
36
+
37
+ Sample of the factory:
38
+
39
+ ```ruby
40
+ # app/fake_api/factory.rb
41
+ class Factory < FakeApi::Factoring
42
+
43
+ # Example of User object
44
+ # you can see that it will generate link to fake image
45
+ factory(:user) do
46
+ {
47
+ id: rand(100),
48
+ first_name: Faker::Name.first_name,
49
+ last_name: Faker::Name.first_name,
50
+ avatar_url: Faker::Avatar.image(size: '128x128'),
51
+ age: rand(100)
52
+ }
53
+ end
54
+
55
+ # heare you can put "relations" to other factories
56
+ # see "author" node
57
+ factory(:project) do
58
+ {
59
+ id: rand(1_000),
60
+ title: Faker::Company.name,
61
+ description: Faker::Company.catch_phrase,
62
+ type: Faker::Company.type,
63
+ author: object(:user)
64
+ }
65
+ end
66
+
67
+ # or have factory which contains from the list of Projects and a single user
68
+ factory(:complex) do
69
+ {
70
+ projects: create_list(:project, 2),
71
+ user: object(:user)
72
+ }
73
+ end
74
+
75
+ end
76
+ ```
77
+
78
+ And sample of routing:
79
+
80
+ ```ruby
81
+ # app/fake_api/app_routing.rb
82
+ class AppRouting < FakeApi::Routing
83
+ get('/projects').and_return { create_list(:project, 5) }.with_status(202).with_headers({TOKEN: "SECRET"})
84
+ get(%r{/projects/\d+$}).and_return { object(:project) }
85
+ post('/projects').and_return { object(:project).merge({created: 'ok'}) }
86
+ delete(%r{/projects/\d+$}).and_return { { result: :deleted } }.with_status(333)
87
+
88
+ post('/auth')
89
+ .and_return { { status: "OK" } }
90
+ .with_cookies({x: "A"})
91
+ .with_session({y: "B"})
92
+ .with_headers({token: "C"})
93
+ end
94
+ ```
95
+
96
+ ## Factory Methods
97
+
98
+ - `create_list(:factory_name, 10)` to create an array of 10 factories.
99
+ - `object(:factory_nane)` to return a factory
100
+
101
+ ## Routing Methods
102
+
103
+ - `get/post/put/patch/delete` to define route
104
+ - `and_return` to specify the response. This response will be converted to FORMAT (json, xml, js, csv(for arrays) etc)
105
+ - `with_cookies` to list returned cookies
106
+ - `with_session` to list changes in session
107
+ - `with_headers` to list returned headers
108
+
109
+ ## TODO
110
+
111
+ - CI (travis, github actions, etc)
112
+ - render ERB?
113
+ - exclude from code converage generator and dummy app
114
+ - make code coverage 100%
115
+
116
+ ## Contributing
117
+
118
+ You are welcome to contribute.
119
+
120
+ ## License
121
+
122
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,32 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'FakeApi'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+ load 'rails/tasks/statistics.rake'
21
+
22
+ require 'bundler/gem_tasks'
23
+
24
+ require 'rake/testtask'
25
+
26
+ Rake::TestTask.new(:test) do |t|
27
+ t.libs << 'test'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+
32
+ task default: :test
File without changes
@@ -0,0 +1,27 @@
1
+ class FakeController < ApplicationController
2
+
3
+ def data
4
+ result = FakeApi::Handler.handle(request.method, path: params[:path], params: params, headers: request.headers)
5
+
6
+ response.status = result.status
7
+
8
+ result.headers.each { |k, v| headers[k.to_s] = v }
9
+ result.cookies.each { |k, v| cookies[k.to_s] = v }
10
+ result.session.each { |k, v| session[k.to_s] = v }
11
+
12
+ respond_to do |format|
13
+ format.html { render plain: result.data.inspect }
14
+ format.xml { render xml: result.data }
15
+ format.json { render json: result.data }
16
+ format.js { render js: result.data }
17
+ format.csv {
18
+ require 'csv'
19
+ csv_string = CSV.generate(headers: false) do |csv|
20
+ result.data.each { |i| csv << i }
21
+ end
22
+ render plain: csv_string
23
+ }
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,6 @@
1
+ FakeApi::Engine.routes.draw do
2
+ match '/*path', to: 'fake#data', via: :all
3
+
4
+ # to get mounted route
5
+ get '/__test__test', to: 'fake#data', as: :__test__test
6
+ end
@@ -0,0 +1,16 @@
1
+ require "fake_api/engine"
2
+ require "faker"
3
+ require "pry"
4
+ require "ostruct"
5
+
6
+ require_relative './fake_api/data.rb'
7
+ require_relative './fake_api/base.rb'
8
+ require_relative './fake_api/route.rb'
9
+ require_relative './fake_api/factory.rb'
10
+ require_relative './fake_api/handler.rb'
11
+ require_relative './fake_api/debug.rb'
12
+
13
+ require_relative './generators/fake_api_generator.rb' rescue nil
14
+
15
+ module FakeApi
16
+ end
@@ -0,0 +1,11 @@
1
+ module FakeApi
2
+ class Base
3
+ mattr_accessor :data
4
+ @@data = FakeApiData.instance
5
+ class << self
6
+ delegate_missing_to :data
7
+ end
8
+ end
9
+ Routing = Base
10
+ Factoring = Base
11
+ end
@@ -0,0 +1,71 @@
1
+ module FakeApi
2
+
3
+ class FakeApiData
4
+ attr_reader :responses, :routes
5
+
6
+ def FakeApiData.instance
7
+ @@instance ||= FakeApiData.new
8
+ end
9
+
10
+ def initialize
11
+ @responses = {}
12
+ @routes = {}
13
+ end
14
+
15
+ def factory(name, &block)
16
+ response = Factory.new(name: name, value: block)
17
+ @responses[name] = response
18
+ end
19
+
20
+ def route(request_method, route:, &block)
21
+ e = Route.new(route: route)
22
+ @routes[request_method.upcase] ||= {}
23
+ @routes[request_method.upcase][route] = e
24
+ end
25
+
26
+ def get(path)
27
+ route("GET", route: path)
28
+ end
29
+
30
+ def post(path)
31
+ route("POST", route: path)
32
+ end
33
+
34
+ def put(path)
35
+ route("PUT", route: path)
36
+ end
37
+
38
+ def patch(path)
39
+ route("PATCH", route: path)
40
+ end
41
+
42
+ def delete(path)
43
+ route("DELETE", route: path)
44
+ end
45
+
46
+ def object(something)
47
+ response_or_value(something)
48
+ end
49
+ alias :create :object
50
+ alias :build :object
51
+
52
+ def create_list(something, amount)
53
+ result = []
54
+ amount.times { result << response_or_value(something) }
55
+ result
56
+ end
57
+
58
+ def response_or_value(e)
59
+ if e.is_a?(Symbol)
60
+ if response = FakeApiData.instance.responses[e]
61
+ response.value.call
62
+ else
63
+ nil
64
+ end
65
+ else
66
+ e
67
+ end
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,42 @@
1
+ module FakeApi
2
+
3
+ class Debug
4
+
5
+ def Debug.status
6
+ result = {}
7
+ result[:factories] = []
8
+ result[:responses] = {}
9
+
10
+ FakeApiData.instance.responses.each do |name, response|
11
+ result[:factories] << name
12
+ end
13
+
14
+ FakeApiData.instance.routes.each do |request_method, info|
15
+ result[:responses][request_method] ||= []
16
+ info.each do |(path, route)|
17
+ result[:responses][request_method] << {
18
+ route: route.route,
19
+ status: route.status
20
+ }
21
+ end
22
+ end
23
+ result
24
+ end
25
+
26
+ end
27
+
28
+ end
29
+
30
+ # module FakeApi
31
+ # extend ActiveSupport::Autoload
32
+
33
+ # eager_autoload do
34
+ # autoload :Handler
35
+ # autoload :Route
36
+ # autoload :Response
37
+ # autoload :Factory
38
+ # autoload :Routing
39
+ # autoload :Handler
40
+ # autoload :FakeApiData
41
+ # end
42
+ # end
@@ -0,0 +1,22 @@
1
+ module FakeApi
2
+ class Engine < ::Rails::Engine
3
+ def Engine.mounted_in
4
+ @mounted_in ||= FakeApi::Engine.routes.url_helpers.__test__test_path.gsub("/__test__test", '')
5
+ end
6
+
7
+ config.to_prepare do
8
+ Engine.load_fake_api_dependencies
9
+ end
10
+
11
+ config.after_initialize do |app|
12
+ app.config.paths.add 'app/fake_api', eager_load: true
13
+ app.config.autoload_paths += Dir["#{Rails.root}/app/fake_api/**/*.rb"]
14
+ end
15
+
16
+ def Engine.load_fake_api_dependencies
17
+ Dir["#{Rails.root}/app/fake_api/**/*.rb"].each do |file|
18
+ require_dependency file
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,14 @@
1
+ module FakeApi
2
+ class Factory
3
+ attr_reader :name, :value
4
+ def initialize(name:, value: nil, &block)
5
+ @name = name
6
+ @value = value || block
7
+ end
8
+
9
+ def returns(new_value = nil, &block)
10
+ @value = new_value || block
11
+ self
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,56 @@
1
+ module FakeApi
2
+ class Handler
3
+
4
+ def Handler.handle(method, path:, params: {}, headers: {})
5
+ if route = Handler.resolve(method, path)
6
+ result(
7
+ data: route.response.call,
8
+ status: route.status,
9
+ headers: route.headers,
10
+ cookies: route.cookies,
11
+ session: route.session
12
+ )
13
+ else
14
+ # READ MORE: https://github.com/igorkasyanchuk/fake_api
15
+ result(
16
+ data: %Q{
17
+ Route "#{FakeApi::Engine.mounted_in}/#{path}" was not found. Please edit your fake_api rounting file(s) in app/fake_api/*.rb.\n\nAvailable:
18
+ \n#{available.presence || 'NONE'}
19
+ }.strip,
20
+ status: 500,
21
+ )
22
+ end
23
+ end
24
+
25
+ def Handler.result(data:, status: 200, headers: {}, cookies: {}, session: {})
26
+ OpenStruct.new(
27
+ data: data,
28
+ status: status,
29
+ headers: headers,
30
+ cookies: cookies,
31
+ session: session
32
+ )
33
+ end
34
+
35
+ private
36
+
37
+ def Handler.resolve(method, path)
38
+ FakeApiData.instance.routes.fetch(method, {}).each do |k, v|
39
+ return v if "/#{path}" == k
40
+ return v if k.is_a?(Regexp) && "/#{path}" =~ k
41
+ end
42
+ nil
43
+ end
44
+
45
+ def Handler.available
46
+ result = []
47
+ FakeApiData.instance.routes.collect do |method, route|
48
+ route.each do |k, v|
49
+ result << "#{method} #{FakeApi::Engine.mounted_in}#{k}"
50
+ end
51
+ end
52
+ result.sort.join("\n")
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,40 @@
1
+ module FakeApi
2
+ class Route
3
+ attr_reader :route, :response, :status, :headers, :cookies, :session
4
+
5
+ def initialize(route:, response: nil, status: 200, headers: {}, cookies: {}, session: {})
6
+ @route = route
7
+ @response = response
8
+ @status = status
9
+ @headers = headers
10
+ @cookies = cookies
11
+ @session = session
12
+ self
13
+ end
14
+
15
+ def with_status(new_status)
16
+ @status = new_status
17
+ self
18
+ end
19
+
20
+ def and_return(new_response = nil, &block)
21
+ @response = new_response || block
22
+ self
23
+ end
24
+
25
+ def with_headers(new_headers)
26
+ @headers = new_headers
27
+ self
28
+ end
29
+
30
+ def with_cookies(new_cookies)
31
+ @cookies = new_cookies
32
+ self
33
+ end
34
+
35
+ def with_session(new_session)
36
+ @session = new_session
37
+ self
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module FakeApi
2
+ VERSION = '0.9.0'
3
+ end
@@ -0,0 +1,20 @@
1
+ class FakeApiGenerator < Rails::Generators::Base
2
+ source_root File.expand_path("templates", __dir__)
3
+
4
+ def create_fake_api_file
5
+ if file_name.blank?
6
+ puts "Sample: rails g fake_api Product"
7
+ exit
8
+ end
9
+ template 'routing.rb', File.join('app/fake_api', "#{file_name}_routing.rb")
10
+ template 'factory.rb', File.join('app/fake_api', "#{file_name}_factory.rb")
11
+ end
12
+
13
+ def class_name
14
+ args[0]&.strip
15
+ end
16
+
17
+ def file_name
18
+ class_name&.underscore
19
+ end
20
+ end
@@ -0,0 +1,29 @@
1
+ class <%= class_name %>Factory < FakeApi::Factoring
2
+
3
+ factory(:user) do
4
+ {
5
+ id: rand(100),
6
+ first_name: Faker::Name.first_name,
7
+ last_name: Faker::Name.first_name,
8
+ avatar_url: Faker::Avatar.image(size: '128x128')
9
+ }
10
+ end
11
+
12
+ factory(:project) do
13
+ {
14
+ id: rand(1_000),
15
+ title: Faker::Company.name,
16
+ description: Faker::Company.catch_phrase,
17
+ type: Faker::Company.type,
18
+ author: object(:user)
19
+ }
20
+ end
21
+
22
+ factory(:complex) do
23
+ {
24
+ projects: create_list(:project, 2),
25
+ user: object(:user)
26
+ }
27
+ end
28
+
29
+ end
@@ -0,0 +1,13 @@
1
+ class <%= class_name %>Routing < FakeApi::Routing
2
+ get('/projects').and_return { create_list(:project, 5) }.with_status(202).with_headers({TOKEN: "SECRET"})
3
+
4
+ get(%r{/projects/\d+$})
5
+ .and_return { object(:project) }
6
+ .with_cookies({x: "A"})
7
+ .with_session({y: "B"})
8
+ .with_headers({token: "C"})
9
+
10
+ post('/projects').and_return { object(:project).merge({created: 'ok'}) }
11
+
12
+ delete(%r{/projects/\d+$}).and_return { { result: :deleted } }.with_status(200)
13
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :fake_api do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fake_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.9.0
5
+ platform: ruby
6
+ authors:
7
+ - Igor Kasyanchuk
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-02-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
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: faker
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: simplecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: The fastest way to prototype API in your Rails app using Faker and mix
84
+ of rails routes, factory bot and faker syntax
85
+ email:
86
+ - igorkasyanchuk@gmail.com
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - MIT-LICENSE
92
+ - README.md
93
+ - Rakefile
94
+ - app/assets/config/fake_api_manifest.js
95
+ - app/controllers/fake_controller.rb
96
+ - config/routes.rb
97
+ - lib/fake_api.rb
98
+ - lib/fake_api/base.rb
99
+ - lib/fake_api/data.rb
100
+ - lib/fake_api/debug.rb
101
+ - lib/fake_api/engine.rb
102
+ - lib/fake_api/factory.rb
103
+ - lib/fake_api/handler.rb
104
+ - lib/fake_api/route.rb
105
+ - lib/fake_api/version.rb
106
+ - lib/generators/fake_api_generator.rb
107
+ - lib/generators/templates/factory.rb
108
+ - lib/generators/templates/routing.rb
109
+ - lib/tasks/fake_api_tasks.rake
110
+ homepage: https://github.com/igorkasyanchuk/fake_api
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '0'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.0.6
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: The fastest way to prototype API in your Rails app.
133
+ test_files: []