pico_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/LICENSE +21 -0
  4. data/Rakefile +5 -0
  5. data/Readme.md +56 -0
  6. data/bin/console +15 -0
  7. data/bin/pico_api +14 -0
  8. data/bin/setup +8 -0
  9. data/lib/pico_api/configuration.rb +30 -0
  10. data/lib/pico_api/database.rb +24 -0
  11. data/lib/pico_api/entities/error.rb +22 -0
  12. data/lib/pico_api/entities/errors.rb +22 -0
  13. data/lib/pico_api/generators/commands/base.rb +45 -0
  14. data/lib/pico_api/generators/commands/copy_template.rb +19 -0
  15. data/lib/pico_api/generators/commands/create_base.rb +29 -0
  16. data/lib/pico_api/generators/commands/create_config_application.rb +19 -0
  17. data/lib/pico_api/generators/commands/create_config_boot.rb +19 -0
  18. data/lib/pico_api/generators/commands/create_config_configuration.rb +19 -0
  19. data/lib/pico_api/generators/commands/create_config_database_setup.rb +19 -0
  20. data/lib/pico_api/generators/commands/create_config_database_yml.rb +19 -0
  21. data/lib/pico_api/generators/commands/create_config_dotenv.rb +19 -0
  22. data/lib/pico_api/generators/commands/create_config_ru.rb +19 -0
  23. data/lib/pico_api/generators/commands/create_gemfile.rb +19 -0
  24. data/lib/pico_api/generators/commands/create_gitignore.rb +19 -0
  25. data/lib/pico_api/generators/commands/create_rakefile.rb +19 -0
  26. data/lib/pico_api/generators/commands/create_template.rb +21 -0
  27. data/lib/pico_api/generators/generator.rb +40 -0
  28. data/lib/pico_api/generators/templates/.gitignore +2 -0
  29. data/lib/pico_api/generators/templates/Gemfile.erb +7 -0
  30. data/lib/pico_api/generators/templates/Rakefile.erb +9 -0
  31. data/lib/pico_api/generators/templates/config/application.erb +5 -0
  32. data/lib/pico_api/generators/templates/config/boot.erb +9 -0
  33. data/lib/pico_api/generators/templates/config/configuration.erb +13 -0
  34. data/lib/pico_api/generators/templates/config/database.yml +8 -0
  35. data/lib/pico_api/generators/templates/config/database_setup.erb +6 -0
  36. data/lib/pico_api/generators/templates/config/dotenv.erb +6 -0
  37. data/lib/pico_api/generators/templates/config.ru.erb +3 -0
  38. data/lib/pico_api/handlers/errors.rb +23 -0
  39. data/lib/pico_api/json_api_renderer.rb +11 -0
  40. data/lib/pico_api/serializers/base.rb +11 -0
  41. data/lib/pico_api/version.rb +5 -0
  42. data/lib/pico_api.rb +30 -0
  43. data/pico_api.gemspec +33 -0
  44. metadata +197 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42f576489c0e3b0b4cc8ab9d23d3dd273f50f3fcd6cf29689b26a67ee6508c3f
4
+ data.tar.gz: 83723e1d3095b13f302d016b8a3f2b166220a7e42842b569ef77cfd86f76648e
5
+ SHA512:
6
+ metadata.gz: 7eb82db803e9e5f78d7c78ecf8a2054dfbd523f200331586e8ac1e9c45c38c837fdae794c4296c593627c97a976382aca69b77a478359d8473e882435dcb936f
7
+ data.tar.gz: 43935b1f888497e2dafc4f488d53ecc4b55fdd48efa112ef6ca659b37cc94c4f8bbdef392ef30857ac0c474490a88d4e60cf8c1c2e2fb0186a6e719727fb17cf
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ *.gem
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2022 Alex Avlonitis
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+
5
+ task default: :spec
data/Readme.md ADDED
@@ -0,0 +1,56 @@
1
+ # Pico API
2
+
3
+ A tiny boilerplate JSON API template in ruby. Its minimal footprint makes it ideal for microservices or even full blown APIs.
4
+ It has been created for those who don't need the RAILS "magic" and bloat. Can easily create different architectures, like STAR, CQRS..., and MVC.
5
+
6
+ Pico API is just a collection of the fastest ruby libraries put together to form a basic API environment, with the JSON:API specification. It doesn't create any folder structures for your business logic, it only creates the initial configurations to get you started.
7
+
8
+ Example demo project can be found [here](https://github.com/alexavlonitis/pico_api_example)
9
+
10
+ ## Libraries Used
11
+
12
+ - [roda](https://github.com/jeremyevans/roda) -> Routing
13
+ - [rom-rb](https://github.com/rom-rb/rom) -> ORM
14
+ - [jsonapi serializer](https://github.com/jsonapi-serializer/jsonapi-serializer) -> Fast-jsonapi fork
15
+
16
+ ## Usage
17
+
18
+ ### Create your app
19
+
20
+ ```ruby
21
+ gem install pico_api
22
+
23
+ pico_api --new my_app
24
+
25
+ cd my_app
26
+
27
+ bundle install
28
+ ```
29
+
30
+ ### Configure your database
31
+
32
+ Migration info: https://rom-rb.org/5.0/learn/sql/migrations/
33
+
34
+ - Add the database config details in `config/database.yml`
35
+ - Setup the Database: `rake db:setup`
36
+ - Create a migration: `rake db:create_migration[create_users]` (include your preferred DB gem in the Gemfile)
37
+ - Run the migrations: `rake db:migrate`
38
+ - Run the server: `rackup -p 3001`
39
+
40
+
41
+ ## Development
42
+ - [x] Create Database config
43
+ - [x] Hook a json-api library
44
+ - [x] Handle Errors
45
+ - [ ] Create a Logger config
46
+ - [ ] Create a testing environment
47
+ - [ ] Allow multiple db gateways in the config
48
+ - [ ] Add irb/pry console script
49
+
50
+ ## Contributing
51
+
52
+ All Pull Requests are welcome, from a single typo to a new feature.
53
+
54
+ - Fork this repo
55
+ - Create a new branch, add your changes with tests when necessary
56
+ - Submit a Pull Request
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'pico_api'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
data/bin/pico_api ADDED
@@ -0,0 +1,14 @@
1
+
2
+ #!/usr/bin/env ruby
3
+
4
+ require 'optparse'
5
+ require 'pico_api'
6
+
7
+ options = {}
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: pico_api [options]"
10
+
11
+ opts.on('-n', '--new project_name') { |o| options[:project_name] = o }
12
+ end.parse!
13
+
14
+ PicoApi::Generators::Generator.call(options[:project_name])
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'erb'
4
+ require 'yaml'
5
+
6
+ module PicoApi
7
+ class << self
8
+ def configuration
9
+ @configuration ||= Configuration.new(db_config)
10
+ end
11
+
12
+ def db_config
13
+ template = ERB.new(File.new('./config/database.yml').read)
14
+ YAML.safe_load(template.result(binding))
15
+ end
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+ end
21
+
22
+ class Configuration
23
+ attr_reader :db_config
24
+ attr_accessor :namespace, :lib_path, :errors_map
25
+
26
+ def initialize(db_config)
27
+ @db_config = db_config
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rom'
4
+ require 'rom-sql'
5
+
6
+ module PicoApi
7
+ class Database
8
+ class << self
9
+ attr_accessor :container
10
+
11
+ def setup!
12
+ database_config = PicoApi.configuration.db_config['default']
13
+ adapter = database_config['adapter'].to_sym
14
+ options = database_config['options'].symbolize_keys
15
+ connection_string = database_config['connection_string']
16
+
17
+ config = ROM::Configuration.new(adapter, connection_string, options)
18
+ yield config if block_given?
19
+
20
+ @container = ROM.container(config)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'securerandom'
4
+
5
+ module PicoApi
6
+ module Entities
7
+ class Error < ROM::Struct
8
+ attribute? :title, ROM::Types::String
9
+ attribute? :status, ROM::Types::String.optional
10
+ attribute? :code, ROM::Types::String.optional
11
+ attribute? :detail, ROM::Types::String.optional
12
+
13
+ def to_h
14
+ id.merge(super)
15
+ end
16
+
17
+ def id
18
+ { id: SecureRandom.hex(5) }
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Entities
5
+ class Errors < ROM::Struct
6
+ class << self
7
+ def call(error)
8
+ class_name = error.class.name.demodulize
9
+ error_entities = [
10
+ Entities::Error.new(
11
+ title: class_name.underscore,
12
+ detail: error.message
13
+ )
14
+ ]
15
+ new(errors: error_entities)
16
+ end
17
+ end
18
+
19
+ attribute? :errors, ROM::Types::Array(Entities::Error)
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require 'erb'
5
+
6
+ module PicoApi
7
+ module Generators
8
+ module Commands
9
+ class Base
10
+ def self.call(project_name)
11
+ new(project_name).call
12
+ end
13
+
14
+ def initialize(project_name)
15
+ @project_name_camelcased = project_name.camelize
16
+ @project_name_snakecased = project_name.underscore
17
+ end
18
+
19
+ def call
20
+ NotImplementError
21
+ end
22
+
23
+ def get_binding
24
+ binding
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :project_name_camelised, :project_name_snakecased
30
+
31
+ def erb
32
+ ERB.new(File.read(template_full_path))
33
+ end
34
+
35
+ def template_full_path
36
+ File.join(PicoApi.lib_path, template_relative_path)
37
+ end
38
+
39
+ def template_relative_path
40
+ ''
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CopyTemplate < Base
7
+ def call
8
+ copy_file
9
+ end
10
+
11
+ private
12
+
13
+ def copy_file
14
+ FileUtils.cp(template_full_path, "#{project_name_snakecased}#{destination_path}")
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateBase < Base
7
+ def call
8
+ create_bin_folder
9
+ create_lib_folder
10
+ create_config_folder
11
+ end
12
+
13
+ private
14
+
15
+ def create_bin_folder
16
+ FileUtils.mkdir_p("#{project_name_snakecased}/bin")
17
+ end
18
+
19
+ def create_lib_folder
20
+ FileUtils.mkdir_p("#{project_name_snakecased}/lib/#{project_name_snakecased}")
21
+ end
22
+
23
+ def create_config_folder
24
+ FileUtils.mkdir_p("#{project_name_snakecased}/config")
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigApplication < CreateTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/application.rb'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/application.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigBoot < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/boot.rb'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/boot.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigConfiguration < CreateTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/configuration.rb'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/configuration.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigDatabaseSetup < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/database_setup.rb'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/database_setup.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigDatabaseYml < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/database.yml'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/database.yml'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigDotenv < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config/dotenv.rb'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config/dotenv.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateConfigRu < CreateTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/config.ru'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/config.ru.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateGemfile < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/Gemfile'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/Gemfile.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateGitignore < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/.gitignore'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/.gitignore'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateRakefile < CopyTemplate
7
+ private
8
+
9
+ def destination_path
10
+ '/Rakefile'
11
+ end
12
+
13
+ def template_relative_path
14
+ '/generators/templates/Rakefile.erb'
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ module Commands
6
+ class CreateTemplate < Base
7
+ def call
8
+ create_file
9
+ end
10
+
11
+ private
12
+
13
+ def create_file
14
+ File.open("#{project_name_snakecased}#{destination_path}", 'w') do |f|
15
+ f.write(erb.result(get_binding))
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Generators
5
+ class Generator
6
+ class << self
7
+ def call(project_name)
8
+ commands = load_commands
9
+ new(project_name, commands).call
10
+ end
11
+
12
+ def load_commands
13
+ skip_commands = %w[base copytemplate createtemplate]
14
+
15
+ Dir[File.join(PicoApi.lib_path, '/generators/commands/*.rb')].sort.map do |file_path|
16
+ file_name = file_path.split('/').last.gsub('.rb', '').camelize
17
+ next if skip_commands.include?(file_name.downcase)
18
+
19
+ "PicoApi::Generators::Commands::#{file_name}".constantize
20
+ end.compact
21
+ end
22
+ end
23
+
24
+ def initialize(project_name, commands = [])
25
+ raise 'Missing project name' unless project_name
26
+
27
+ @project_name = project_name
28
+ @commands = commands
29
+ end
30
+
31
+ def call
32
+ commands.each { |command| command.call(project_name) }
33
+ end
34
+
35
+ private
36
+
37
+ attr_reader :project_name, :commands
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,2 @@
1
+ .env
2
+ *.db
@@ -0,0 +1,7 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "pico_api"
4
+
5
+ group :development, :test do
6
+ gem "dotenv"
7
+ end
@@ -0,0 +1,9 @@
1
+ require "pico_api"
2
+ require "./config/dotenv"
3
+ require 'rom/sql/rake_task'
4
+
5
+ namespace :db do
6
+ task :setup do
7
+ ROM::SQL::RakeSupport.env = ROM.container(default: [:sql, ENV.fetch("DB_CONNECTION_STRING")])
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module <%= @project_name_camelcased %>
2
+ class Application < PicoApi::Application
3
+ # Add routing instructions here. https://github.com/jeremyevans/roda
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ require "pico_api"
2
+ require "./config/dotenv" if ENV['PICO_API_ENV'] == "development"
3
+ require "./config/configuration"
4
+ require "./config/database_setup"
5
+ require "./config/application"
6
+
7
+ loader = Zeitwerk::Loader.new
8
+ loader.push_dir("./lib")
9
+ loader.setup
@@ -0,0 +1,13 @@
1
+ PicoApi.configure do |config|
2
+ ## the base namespace of your app
3
+ config.namespace = "<%= @project_name_camelcased %>"
4
+
5
+ ## the root directory where all the business logic resides
6
+ config.lib_path = "lib/<%= @project_name_snakecased %>"
7
+
8
+ ## Add your custom exception mappings -> { exception: status_code }.
9
+ # PicoApi serializes runtime exceptions to json-api specification error objects
10
+ config.errors_map = {
11
+ StandardError: :unprocessable_entity
12
+ }.freeze
13
+ end
@@ -0,0 +1,8 @@
1
+ # https://rom-rb.org/5.0/learn/sql/#general-connection-options
2
+
3
+ default:
4
+ adapter:
5
+ connection_string:
6
+ options:
7
+ encoding:
8
+
@@ -0,0 +1,6 @@
1
+ PicoApi::Database.setup! do |config|
2
+ config.auto_registration(
3
+ File.expand_path(PicoApi.configuration.lib_path, './'),
4
+ namespace: PicoApi.configuration.namespace
5
+ )
6
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ unless ENV["RACK_ENV"] == "production"
4
+ require "dotenv"
5
+ Dotenv.overload ".env", ".env.local", ".env.#{ENV.fetch('RACK_ENV', nil)}"
6
+ end
@@ -0,0 +1,3 @@
1
+ require './config/boot'
2
+
3
+ run <%= @project_name_camelcased %>::Application.freeze.app
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module Handlers
5
+ class Errors
6
+ def self.call(error, response)
7
+ exception_key = error.class.name.demodulize.to_sym
8
+ status = PicoApi.configuration.errors_map[exception_key]
9
+ return system_error(error, response) unless status
10
+
11
+ response.status = status
12
+ Entities::Errors.call(error).to_h
13
+ end
14
+
15
+ ServerError = Struct.new(:message)
16
+ def self.system_error(error, response)
17
+ response.status = :internal_server_error
18
+ error = ServerError.new('Something went wrong, we are investigating')
19
+ Entities::Errors.call(error).to_h
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ module JsonApiRenderer
5
+ def serialize(resource, **opts)
6
+ serializer_klass = opts.delete(:serializer)
7
+ serializer = serializer_klass.new(resource, opts)
8
+ serializer.serializable_hash
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'jsonapi/serializer'
4
+
5
+ module PicoApi
6
+ module Serializers
7
+ class Base
8
+ include JSONAPI::Serializer
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PicoApi
4
+ VERSION = '0.0.1'
5
+ end
data/lib/pico_api.rb ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'roda'
4
+ require 'zeitwerk'
5
+
6
+ loader = Zeitwerk::Loader.for_gem
7
+ loader.setup
8
+
9
+ module PicoApi
10
+ def self.root_path
11
+ File.dirname(__dir__)
12
+ end
13
+
14
+ def self.lib_path
15
+ File.join(root_path, 'lib/pico_api')
16
+ end
17
+
18
+ class Application < Roda
19
+ parser = proc { |data| JSON.parse(data, symbolize_names: true) }
20
+
21
+ plugin :symbol_status
22
+ plugin :json_parser, parser: parser
23
+ plugin :json, content_type: 'application/vnd.api+json'
24
+ plugin :error_handler do |e|
25
+ PicoApi::Handlers::Errors.call(e, response)
26
+ end
27
+ end
28
+ end
29
+
30
+ loader.eager_load
data/pico_api.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/pico_api/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'pico_api'
7
+ spec.version = PicoApi::VERSION
8
+ spec.authors = ['Alex Avlonitis']
9
+
10
+ spec.summary = 'A tiny Rack-based ruby template for APIs'
11
+ spec.description = 'A tiny Rack-based ruby template for APIs'
12
+ spec.homepage = 'https://github.com/alexavlonitis/pico_api'
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
14
+
15
+ spec.metadata['homepage_uri'] = spec.homepage
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.require_paths = ['lib']
23
+ spec.executables << 'pico_api'
24
+
25
+ spec.add_runtime_dependency 'erb', '~> 2.2.3'
26
+ spec.add_runtime_dependency 'jsonapi-serializer', '~> 2.2.0'
27
+ spec.add_runtime_dependency 'rackup', '~> 0.2.2'
28
+ spec.add_runtime_dependency 'rake', '~> 13.0.6'
29
+ spec.add_runtime_dependency 'roda', '~> 3.61.0'
30
+ spec.add_runtime_dependency 'rom', '~> 5.2.6'
31
+ spec.add_runtime_dependency 'rom-sql', '~> 3.5.0'
32
+ spec.add_runtime_dependency 'zeitwerk', '~> 2.6.1'
33
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pico_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Alex Avlonitis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-10-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: erb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.2.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.2.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: jsonapi-serializer
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 2.2.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 2.2.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: rackup
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.2.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.2.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 13.0.6
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 13.0.6
69
+ - !ruby/object:Gem::Dependency
70
+ name: roda
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.61.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.61.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rom
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 5.2.6
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 5.2.6
97
+ - !ruby/object:Gem::Dependency
98
+ name: rom-sql
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 3.5.0
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 3.5.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: zeitwerk
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 2.6.1
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 2.6.1
125
+ description: A tiny Rack-based ruby template for APIs
126
+ email:
127
+ executables:
128
+ - pico_api
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - LICENSE
134
+ - Rakefile
135
+ - Readme.md
136
+ - bin/console
137
+ - bin/pico_api
138
+ - bin/setup
139
+ - lib/pico_api.rb
140
+ - lib/pico_api/configuration.rb
141
+ - lib/pico_api/database.rb
142
+ - lib/pico_api/entities/error.rb
143
+ - lib/pico_api/entities/errors.rb
144
+ - lib/pico_api/generators/commands/base.rb
145
+ - lib/pico_api/generators/commands/copy_template.rb
146
+ - lib/pico_api/generators/commands/create_base.rb
147
+ - lib/pico_api/generators/commands/create_config_application.rb
148
+ - lib/pico_api/generators/commands/create_config_boot.rb
149
+ - lib/pico_api/generators/commands/create_config_configuration.rb
150
+ - lib/pico_api/generators/commands/create_config_database_setup.rb
151
+ - lib/pico_api/generators/commands/create_config_database_yml.rb
152
+ - lib/pico_api/generators/commands/create_config_dotenv.rb
153
+ - lib/pico_api/generators/commands/create_config_ru.rb
154
+ - lib/pico_api/generators/commands/create_gemfile.rb
155
+ - lib/pico_api/generators/commands/create_gitignore.rb
156
+ - lib/pico_api/generators/commands/create_rakefile.rb
157
+ - lib/pico_api/generators/commands/create_template.rb
158
+ - lib/pico_api/generators/generator.rb
159
+ - lib/pico_api/generators/templates/.gitignore
160
+ - lib/pico_api/generators/templates/Gemfile.erb
161
+ - lib/pico_api/generators/templates/Rakefile.erb
162
+ - lib/pico_api/generators/templates/config.ru.erb
163
+ - lib/pico_api/generators/templates/config/application.erb
164
+ - lib/pico_api/generators/templates/config/boot.erb
165
+ - lib/pico_api/generators/templates/config/configuration.erb
166
+ - lib/pico_api/generators/templates/config/database.yml
167
+ - lib/pico_api/generators/templates/config/database_setup.erb
168
+ - lib/pico_api/generators/templates/config/dotenv.erb
169
+ - lib/pico_api/handlers/errors.rb
170
+ - lib/pico_api/json_api_renderer.rb
171
+ - lib/pico_api/serializers/base.rb
172
+ - lib/pico_api/version.rb
173
+ - pico_api.gemspec
174
+ homepage: https://github.com/alexavlonitis/pico_api
175
+ licenses: []
176
+ metadata:
177
+ homepage_uri: https://github.com/alexavlonitis/pico_api
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: 2.3.0
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubygems_version: 3.1.6
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: A tiny Rack-based ruby template for APIs
197
+ test_files: []