Compare commits

...

17 Commits

Author SHA1 Message Date
Clemens Kofler
7db80f673d Clarify README wording related to contributions 2022-04-04 18:52:58 +01:00
Peter Goldstein
bcee2b597b Add Ruby 3.1 to CI
Also fixes the unquoted 3.0, which needs to be quoted to avoid truncation
Addresses a few Rubocop issues and an active_support require issue on Rails 7 w/Zeitwerk
2022-02-02 21:40:34 +00:00
Igor Victor
44cf8495ea Update ci.yml 2021-04-12 11:50:08 +01:00
Stas SUȘCOV
37235057df
Version bump. 2021-03-11 18:35:11 +00:00
Stas SUȘCOV
c21f9def8f Updated the changelog. 2021-03-11 18:33:35 +00:00
Stas SUȘCOV
8b74954478 Added ruby v3 to CI matrix. 2021-03-11 18:33:35 +00:00
Stas SUȘCOV
ef93f7f358 Make rubocop happy. 2021-03-11 18:33:35 +00:00
HubertVonHerbert
c5eb1ce27c
Fix Ruby3 compatibility issue with Procs (#160)
* Fix Ruby3 compatibility issue with Procs

* Fix rubocop complaints

* Remove ruby 3 from CI actions

* Simplify check for &:foo procs
2021-03-11 18:29:59 +00:00
Ryan Romanchuk
a25d415b4d Fix most likely copy/paste error
this lambda yielding a bool for `belongs_to` might confuse readers or conflate the :if block

which would probably look something like this 

```ruby
belongs_to :primary_agent, if: proc { |movie, params| params[:current_user].present? } do |movie, params|
    # in here, params is a hash containing the `:current_user` key
    params[:current_user]
  end
```
2021-02-14 22:17:08 +00:00
Stas SUȘCOV
c3376037e7 Let everyone know there's a WIP branch for v3. 2021-01-11 11:11:24 +00:00
Yaroslav Kasperovych
963cd77900 Fix require clause in fastjson migration guide
Seems like the require clause should be different as it produces an error if used as it is right now.
2020-11-06 10:15:26 +00:00
Tony Dehnke
98dd59884c Fix namespace name per comment in #139 2020-10-26 12:01:52 +00:00
Guillaume Briday
b7e8a30833 Fix typo in readme 2020-10-25 18:13:08 +00:00
Guillaume Briday
f4ed4f0440 Adding migration section 2020-10-25 17:23:20 +00:00
Jorge Garcia
88061bcfac Add deserialization options on Readme 2020-10-08 10:21:20 +01:00
nattfodd
f8255771dc Raise FastJsonapi scoped error in case of unsupported include 2020-09-18 13:12:41 +03:00
Donatas Povilaitis
1bcf8d2cb5
Do not add empty relationships key (#116) 2020-09-01 20:44:08 +01:00
20 changed files with 181 additions and 26 deletions

View File

@ -4,16 +4,16 @@ on: [push, pull_request]
jobs:
tests:
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
strategy:
matrix:
ruby: [2.4, 2.5, 2.6, 2.7]
ruby: [2.4, 2.7, '3.0', 3.1, truffleruby-head]
steps:
- uses: actions/checkout@master
- name: Sets up the Ruby version
uses: actions/setup-ruby@v1
uses: ruby/setup-ruby@v1
with:
ruby-version: ${{ matrix.ruby }}

View File

@ -2,6 +2,10 @@ require:
- rubocop-performance
- rubocop-rspec
AllCops:
NewCops: enable
SuggestExtensions: false
Style/FrozenStringLiteralComment:
Enabled: false
@ -38,6 +42,9 @@ Performance/TimesMap:
Exclude:
- 'spec/**/**.rb'
Gemspec/RequiredRubyVersion:
Enabled: false
# TODO: Fix these...
Style/Documentation:
Enabled: false
@ -76,3 +83,20 @@ Naming/PredicateName:
Naming/AccessorMethodName:
Exclude:
- 'lib/**/**.rb'
Style/CaseLikeIf:
Exclude:
- 'lib/fast_jsonapi/object_serializer.rb'
Style/OptionalBooleanParameter:
Exclude:
- 'lib/fast_jsonapi/serialization_core.rb'
- 'lib/fast_jsonapi/relationship.rb'
Lint/DuplicateBranch:
Exclude:
- 'lib/fast_jsonapi/relationship.rb'
Style/DocumentDynamicEvalDefinition:
Exclude:
- 'lib/extensions/has_one.rb'

View File

@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- ...
## [2.2.0] - 2021-03-11
### Added
- Proper error is raised on unsupported includes (#125)
### Changed
- Documentation updates (#137 #139 #143 #146)
### Fixed
- Empty relationships are no longer added to serialized doc (#116)
- Ruby v3 compatibility (#160)
## [2.1.0] - 2020-08-30
### Added

View File

@ -1,5 +1,11 @@
# JSON:API Serialization Library
## :warning: :construction: v2 (the `master` branch) is in maintenance mode! :construction: :warning:
We'll gladly accept bugfixes and security-related fixes for v2 (the `master` branch), but at this stage, contributions for new features/improvements are welcome only for v3. Please feel free to leave comments in the [v3 Pull Request](https://github.com/jsonapi-serializer/jsonapi-serializer/pull/141).
---
A fast [JSON:API](https://jsonapi.org/) serializer for Ruby Objects.
Previously this project was called **fast_jsonapi**, we forked the project
@ -39,6 +45,8 @@ article in the `docs` folder for any questions related to methodology.
* [Sparse Fieldsets](#sparse-fieldsets)
* [Using helper methods](#using-helper-methods)
* [Performance Instrumentation](#performance-instrumentation)
* [Deserialization](#deserialization)
* [Migrating from Netflix/fast_jsonapi](#migrating-from-netflixfast_jsonapi)
* [Contributing](#contributing)
@ -458,7 +466,7 @@ class MovieSerializer
belongs_to :primary_agent do |movie, params|
# in here, params is a hash containing the `:current_user` key
params[:current_user].is_employee? ? true : false
params[:current_user]
end
end
@ -693,6 +701,61 @@ tests. To run tests use the following command:
rspec
```
## Deserialization
We currently do not support deserialization, but we recommend to use any of the next gems:
### [JSONAPI.rb](https://github.com/stas/jsonapi.rb)
This gem provides the next features alongside deserialization:
- Collection meta
- Error handling
- Includes and sparse fields
- Filtering and sorting
- Pagination
## Migrating from Netflix/fast_jsonapi
If you come from [Netflix/fast_jsonapi](https://github.com/Netflix/fast_jsonapi), here is the instructions to switch.
### Modify your Gemfile
```diff
- gem 'fast_jsonapi'
+ gem 'jsonapi-serializer'
```
### Replace all constant references
```diff
class MovieSerializer
- include FastJsonapi::ObjectSerializer
+ include JSONAPI::Serializer
end
```
### Replace removed methods
```diff
- json_string = MovieSerializer.new(movie).serialized_json
+ json_string = MovieSerializer.new(movie).serializable_hash.to_json
```
### Replace require references
```diff
- require 'fast_jsonapi'
+ require 'jsonapi/serializer'
```
### Update your cache options
See [docs](https://github.com/jsonapi-serializer/jsonapi-serializer#caching).
```diff
- cache_options enabled: true, cache_length: 12.hours
+ cache_options store: Rails.cache, namespace: 'jsonapi-serializer', expires_in: 1.hour
```
## Contributing
Please follow the instructions we provide as part of the issue and

View File

@ -33,4 +33,5 @@ Gem::Specification.new do |gem|
gem.add_development_dependency('rubocop-rspec')
gem.add_development_dependency('simplecov')
gem.add_development_dependency('sqlite3')
gem.metadata['rubygems_mfa_required'] = 'true'
end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'jsonapi/serializer/errors'
module FastJsonapi
require 'fast_jsonapi/object_serializer'
if defined?(::Rails)

View File

@ -6,7 +6,16 @@ module FastJsonapi
# @param [Array<Object>] *params any number of parameters to be passed to the Proc
# @return [Object] the result of the Proc call with the supplied parameters
def call_proc(proc, *params)
# The parameters array for a lambda created from a symbol (&:foo) differs
# from explictly defined procs/lambdas, so we can't deduce the number of
# parameters from the array length (and differs between Ruby 2.x and 3).
# In the case of negative arity -- unlimited/unknown argument count --
# just send the object to act as the method receiver.
if proc.arity.negative?
proc.call(params.first)
else
proc.call(*params.take(proc.parameters.length))
end
end
end
end

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require 'active_support'
require 'active_support/time'
require 'active_support/concern'
require 'active_support/inflector'
@ -133,9 +134,7 @@ module FastJsonapi
def reflected_record_type
return @reflected_record_type if defined?(@reflected_record_type)
@reflected_record_type ||= begin
name.split('::').last.chomp('Serializer').underscore.to_sym if name&.end_with?('Serializer')
end
@reflected_record_type ||= (name.split('::').last.chomp('Serializer').underscore.to_sym if name&.end_with?('Serializer'))
end
def set_key_transform(transform_name)
@ -228,10 +227,10 @@ module FastJsonapi
# TODO: Remove this undocumented option.
# Delegate the caching to the serializer exclusively.
if !relationship.cached
uncachable_relationships_to_serialize[relationship.name] = relationship
else
if relationship.cached
cachable_relationships_to_serialize[relationship.name] = relationship
else
uncachable_relationships_to_serialize[relationship.name] = relationship
end
relationships_to_serialize[relationship.name] = relationship
end
@ -302,7 +301,7 @@ module FastJsonapi
def serializer_for(name)
namespace = self.name.gsub(/()?\w+Serializer$/, '')
serializer_name = name.to_s.demodulize.classify + 'Serializer'
serializer_name = "#{name.to_s.demodulize.classify}Serializer"
serializer_class_name = namespace + serializer_name
begin
serializer_class_name.constantize
@ -340,9 +339,9 @@ module FastJsonapi
def validate_includes!(includes)
return if includes.blank?
parse_includes_list(includes).keys.each do |include_item|
parse_includes_list(includes).each_key do |include_item|
relationship_to_include = relationships_to_serialize[include_item]
raise ArgumentError, "#{include_item} is not specified as a relationship on #{name}" unless relationship_to_include
raise(JSONAPI::Serializer::UnsupportedIncludeError.new(include_item, name)) unless relationship_to_include
relationship_to_include.static_serializer # called for a side-effect to check for a known serializer class.
end

View File

@ -12,12 +12,12 @@ module FastJsonapi
object_block:,
serializer:,
relationship_type:,
cached: false,
polymorphic:,
conditional_proc:,
transform_method:,
links:,
meta:,
cached: false,
lazy_load_data: false
)
@owner = owner

View File

@ -1,5 +1,6 @@
# frozen_string_literal: true
require 'active_support'
require 'active_support/concern'
require 'digest/sha1'
@ -71,12 +72,11 @@ module FastJsonapi
record_hash = cache_store_instance.fetch(record, **cache_opts) do
temp_hash = id_hash(id_from_record(record, params), record_type, true)
temp_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?
temp_hash[:relationships] = {}
temp_hash[:relationships] = relationships_hash(record, cachable_relationships_to_serialize, fieldset, includes_list, params) if cachable_relationships_to_serialize.present?
temp_hash[:links] = links_hash(record, params) if data_links.present?
temp_hash
end
record_hash[:relationships] = record_hash[:relationships].merge(relationships_hash(record, uncachable_relationships_to_serialize, fieldset, includes_list, params)) if uncachable_relationships_to_serialize.present?
record_hash[:relationships] = (record_hash[:relationships] || {}).merge(relationships_hash(record, uncachable_relationships_to_serialize, fieldset, includes_list, params)) if uncachable_relationships_to_serialize.present?
else
record_hash = id_hash(id_from_record(record, params), record_type, true)
record_hash[:attributes] = attributes_hash(record, fieldset, params) if attributes_to_serialize.present?

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module JSONAPI
module Serializer
class Error < StandardError; end
class UnsupportedIncludeError < Error
attr_reader :include_item, :klass
def initialize(include_item, klass)
super()
@include_item = include_item
@klass = klass
end
def message
"#{include_item} is not specified as a relationship on #{klass}"
end
end
end
end

View File

@ -1,3 +1,4 @@
require 'active_support'
require 'active_support/notifications'
module JSONAPI

View File

@ -1,5 +1,5 @@
module JSONAPI
module Serializer
VERSION = '2.1.0'.freeze
VERSION = '2.2.0'.freeze
end
end

View File

@ -1,3 +1,6 @@
require 'active_support'
require 'active_support/cache'
class User
attr_accessor :uid, :first_name, :last_name, :email
@ -26,3 +29,12 @@ class UserSerializer
}
end
end
module Cached
class UserSerializer < ::UserSerializer
cache_options(
store: ActiveSupport::Cache::MemoryStore.new,
namespace: 'test'
)
end
end

View File

@ -1,3 +1,4 @@
require 'active_support'
require 'active_support/cache'
require 'jsonapi/serializer/instrumentation'

View File

@ -26,7 +26,7 @@ class Movie
@url ||= FFaker::Internet.http_url
return @url if obj.nil?
@url + '?' + obj.hash.to_s
"#{@url}?#{obj.hash}"
end
def owner=(ownr)
@ -48,8 +48,9 @@ class MovieSerializer
set_type :movie
attribute :released_in_year, &:year
attributes :name
attribute :release_year do |object|
attribute :release_year do |object, _params|
object.year
end

View File

@ -25,6 +25,16 @@ RSpec.describe JSONAPI::Serializer do
cache_store.delete(actor.movies[0].owner, namespace: 'test')
).to be(false)
end
context 'without relationships' do
let(:user) { User.fake }
let(:serialized) { Cached::UserSerializer.new(user).serializable_hash.as_json }
it do
expect(serialized['data']).not_to have_key('relationships')
end
end
end
describe 'with caching and different fieldsets' do

View File

@ -18,7 +18,7 @@ RSpec.describe JSONAPI::Serializer do
it do
expect { ActorSerializer.new(actor, include: ['bad_include']) }
.to raise_error(
ArgumentError, /bad_include is not specified as a relationship/
JSONAPI::Serializer::UnsupportedIncludeError, /bad_include is not specified as a relationship/
)
end
end

View File

@ -10,10 +10,8 @@ RSpec.describe JSONAPI::Serializer do
it do
payload = event_name = nil
notification_name = (
::JSONAPI::Serializer::Instrumentation::NOTIFICATION_NAMESPACE +
'serializable_hash'
)
notification_name =
"#{::JSONAPI::Serializer::Instrumentation::NOTIFICATION_NAMESPACE}serializable_hash"
ActiveSupport::Notifications.subscribe(
notification_name

View File

@ -6,6 +6,7 @@ SimpleCov.start do
end
SimpleCov.minimum_coverage 90
require 'active_support'
require 'active_support/core_ext/object/json'
require 'jsonapi/serializer'
require 'ffaker'