restpack / restpack_serializer Goto Github PK
View Code? Open in Web Editor NEWModel serialization, paging, side-loading and filtering
License: MIT License
Model serialization, paging, side-loading and filtering
License: MIT License
See: #89 (comment)
http://localhost:3000/api/v1/messages?include=comments
The comments are included but the array of comment ids in the links element of the parent is missing:
{
-messages: [
-{
id: "1"
text: "hello world"
app_id: 1
user_id: 1
care_group_id: 1
updated_at: "2014-05-01T14:00:07.000Z"
href: "/messages/1"
-links: {
user: "1"
}
}
]
-linked: {
-comments: [
-{
id: "1"
text: "I say. How splendid"
message_id: 1
user_id: null
href: "/comments/1"
Code snippets below:
class Message < ActiveRecord::Base
attr_accessible :user, :comments
has_many :comments
belongs_to :user
attr_accessible :text, :app, :user
end
class Comment < ActiveRecord::Base
attr_accessible :id, :text, :user, :message
belongs_to :message
belongs_to :user
end
class MessageSerializer
include RestPack::Serializer
attributes :id, :text, :app_id, :user_id, :updated_at, :href
can_include :users, :comments
end
class CommentSerializer
include RestPack::Serializer
attributes :id, :text, :message_id, :user_id, :href
can_include :users
end
...which will explain more advanced serialization options
We should be able to set a base URL which will be used in href
and links
as_json
doesn't return json, it returns a hash. Perhaps replace with as_hash
or serialize
?
This will be the equivalent of:
def href
"#{RestPack::Serializer.href_prefix}/songs/#{id}.json"
end
Perhaps all serializers should include this by default?
Just noticed that to_sym
is being call on (what I believe is) user input.
Symbols stay in memory forever, and the more you create, the more memory will be used up.
As per json-api, ids should be strings
Is it possible to define paging as false?
render json: AlbumSerializer.page(params)
So that the above line returns all albums?
previous_href and next_href assume either top level namespace or use a global config.
It would be great if the paging would support nested routes such as
next_href: user/1/comments?page=2
Supporting comma delimited string will allow us to pass the parms to the serializer directly:
URL: /api/v1/channels.json?includes=applications,domains,configurations
render json: ChannelSerializer.page(params)
as well as passing in a hash:
ChannelSerializer.page({page_size: 100, includes: [:applications, :domains, :configurations]})
Include a list of :includes in the meta data for the primary resource
As per http://jsonapi.org/, represent relationships in links
format:
{
"links": {
"posts.author": {
"href": "http://example.com/people/{posts.author}",
"type": "people"
},
"posts.comments": {
"href": "http://example.com/comments/{posts.comments}",
"type": "comments"
}
}
"posts": [{
"id": "1",
"title": "Rails is Omakase",
"links": {
"author": 9,
"comments": [ 1, 2, 3 ]
}, {
"id": "2",
"title": "The Parley Letter",
"links": {
"author": 9,
"comments": [ 4, 5 ]
}, {
"id": "1",
"title": "Dependency Injection is Not a Virtue",
"links": {
"author": 9,
"comments": [ 6 ]
}
}],
"people": [{
"id": "9",
"name": "@d2h"
}],
"comments": [{
"id": "1",
"body": "Mmmmmakase"
}, {
"id": "2",
"body": "I prefer unagi"
}, {
"id": "3",
"body": "What's Omakase?"
}, {
"id": "4",
"body": "Parley is a discussion, especially one between enemies"
}, {
"id": "5",
"body": "The parsley letter"
}, {
"id": "6",
"body": "Dependency Injection is Not a Vice"
}]
}
Based on this dicusssion, we'd like to improve the range of matching options when filtering.
We currently support only exact matching, but !=
, >
, <
, between
and in
would all be useful.
Here are some of the discussion points:
This currently doesn't work as the side-loaded serializer needs to exist in the global namespace. We should assume that serializers live in the same namespace.
module Namespace
class PostSerializer
include RestPack::Serializer
can_include :categories
end
end
module Namespace
class CategorySerializer
include RestPack::Serializer
end
end
SQLite3::SQLException: no such column: albums.album_id: SELECT
through option is ignored when a model defined has_many through association
Is there object caching support? and if not how can i achieve this here?
can only can the side-loading include working if I load all the serializer like the sample program
is it required ? how about put that requirement in readme too ?
Support implicit model filtering on:
belongs_to
relationshipsFiltering will work as follows:
GET /albums.json?ids=1,2,3,4
will return four albums
GET /albums.json?artist_id=10
will return a page of albums
for artist_id=10
GET /albums.json?artist_id=10&genre_ids=2,3,4
will return a page of albums
for artist_id=10
which have a genre
of either 2
, 3
or 4
GET /albums.json?artist_ids=10,11,12
will return a page of albums
for three artists
....when it has been decided: json-api/json-api#7
Adding support for identify filters will be a nice improvement. We should aim to support filter operations other than identify in the future, and the API for this should be forward looking.
Specifying Serializer Filters
can_filter_by
will allow one or more filters to be defined. All primary and foreign keys are filterable by default.
module RestPack::Account::Service::Serializers
class Account
include RestPack::Serializer
attributes :id, :application_id, :created_by, :name, :href
can_filter_by :application_id
end
end
This would remove the need for a custom scope on commands like this:
Is similar functionality as https://github.com/rails-api/active_model_serializers#attributes available in RestPack?
I have the feeling Restpack has a small feature set at this moment. Is that the intention or will the feature set grow with time?
I'd like to contribute.
Currently all :belongs_to foreign keys are filterable:
def filterable_by
filters = [self.model_class.primary_key.to_sym]
filters += self.model_class.reflect_on_all_associations(:belongs_to).map(&:foreign_key).map(&:to_sym)
filters.uniq
end
We should only allow FKs where the relation has been whitelisted: #4
Serializers should allow a whitelist of valid relations to be defined. This will allow us to reject any unwanted side-loads from URLs such as:
/api/v1/application.json?includes=private_model
The white list will be specified by side_load
in the Serializer:
class AlbumSerializer
include RestPack::Serializer
attributes :id, :title, :year, :artist_id
can_include :artist, :songs
end
Similarly to Serializer.resource(params)
, this will find and serialize a single resource but it will exclude paging info and other meta data.
It would be very useful to set a maximum page_size that is allowed, especially for public APIs it would be very bad of having one loading 1000000 records.
Something like kaminari's .max_page_size. Setting it to a value it will load only up to that amount of records per page and no more.
p.s. awesome gem!
Whatever format ember-data
currently uses by default
:can_include
should verify that the requested relation is valid and raise an exception if it isn't.
The spec has changed:
DEPRECATION WARNING: Using #scope without passing a callable object is deprecated. For example scope :red, where(color: 'red')
should be changed to scope :red, -> { where(color: 'red') }
. There are numerous gotchas in the former usage and it makes the implementation more complicated and buggy. (If you prefer, you can just define a class method named self.red
.). (called from class:Album at /Users/gavin/dev/RestPack/restpack_serializer/spec/fixtures/db.rb:53)
https://github.com/RestPack/restpack-core-service is rendering this:
{
channel: "32",
application: "44",
domain: ""
}
Should we include the domain key? If so, should it be null?
These will be similar to page
and page_with_options
but will return a single resource.
I need to alter the query made by methods such as page
and resource
before execution, to gain finer control over transactions, for example.
Do you support inclusion of this feature into your project ?
I'd be willing to discusss technical details and PR.
@context
:custom_attributes
#56
Clients should know where to get the next, previous, first and last pages
The response should have a single meta
key which should contain all meta data for the response.
{
"songs": [
{
"id": 4,
"title": "How to Dissapear Completely",
"album_id": 1,
"artist_id": 1,
"href": "/songs/4.json"
},
{
"id": 5,
"title": "Treedfingers",
"album_id": 1,
"artist_id": 1,
"href": "/songs/5.json"
},
{
"id": 6,
"title": "Optimistic",
"album_id": 1,
"artist_id": 1,
"href": "/songs/6.json"
}
],
"meta": {
"songs": {
"page": 2,
"page_size": 3,
"count": 42,
"includes": [],
"page_count": 14,
"previous_page": 1,
"next_page": 3
}
}
}
This will represent the result of page
and resource
and will allow us to refactor this ugly code:
This will avoid errors where a model's relations don't have custom serializers defined. The default serializer can be minimal, perhaps even containing just the ID
Also, what should the page size be by default?
Serializer.page(params)
currently accepts a hash of params from a GET request. We'd like to reuse the paging mechanism when side-loading, so let's create a page_with_options
method which accepts a RestPack::Serialization::Options
instance.
we have role serializer:
class RoleSerializer
include RestPack::Serializer
attributes :id, :name, :purpose
can_include :role_scopes
end
and a role_scope_seriazlier:
class RoleScopeSerializer
include RestPack::Serializer
attributes :id, :description
end
when we to include role_scopes in the role seralization:
RoleSerializer.page({id: 23, includes: 'role_scopes'})
it throws NameError: uninitialized constant RoleScopeserializer
.
Which comes from this method:
class RestPack::Serializer::Factory
# ...
def self.classify(identifier)
begin
"#{identifier}Serializer".classify.constantize.new
rescue
"#{identifier.to_s.singularize.to_sym}Serializer".classify.constantize.new
end
"role_scopeSerializer".classify
turns into "RoleScopeserializer"
. All that's needed is to change "Serializer" into "_Serializer" in both clauses.
"links": {
"songs.artists": {
"href": "/artists/{songs.artist}.json",
"type": "artists"
},
"songs.albums": {
"href": "/albums/{songs.album}.json",
"type": "albums"
}
}
should be
"links": {
"songs.artist": {
"href": "/artists/{songs.artist}.json",
"type": "artists"
},
"songs.album": {
"href": "/albums/{songs.album}.json",
"type": "albums"
}
}
When dealing with can_include
links, has_many
and belongs_to
relationships behave differently.
When a resource belongs_to
an association (e.g., an album belongs to an artist), that association link is automatically included in the json. However, has_many
resources are not included until you specifically include that resource via the params.
and then
In my implementation of has_many, through
(see PR #80 ), I implemented it in a similar fashion to belongs_to
, so it also automatically includes those links in the json.
I'm not sure what the intended behavior is, but the inconsistency is a little strange/confusing. Is there an intended behavior to work towards?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.