FastJsonapi ID Mandatory Field on Post Request, Unprocessable Entity?

1.1k views Asked by At

I have added this gem in my project for json serialization: gem 'jsonapi-serializer'

On post requests, I receive the following error in create:
FastJsonapi::MandatoryField (id is a mandatory field in the jsonapi spec)

My model is very simple:

class Post < ApplicationRecord
    belongs_to :profile
    belongs_to :category
    validates :title, presence: true
    validates :content, presence: true
    validates :category_id, presence: true
    validates :profile_id, presence: true
end

The save part of this method in the post controller is where the issue arises:

    def create
            @post = Post.new(post_params)
 
            if @post.save
                render json: PostSerializer.new(@post).serializable_hash.as_json, status: :created
            else
                render json: PostSerializer.new(@post.errors).serializable_hash.as_json, status: :unprocessable_entity
            end
    end

In my post request, I used JSON.Stringify() which console log prints:
{"title":"Hello","content":"Hello World","category_id":"1","profile_id":"1"}

Rails' print of the parameters:

Parameters: {"title"=>"Hello", "content"=>"Hello World", "category_id"=>"1", "profile_id"=>"1", "post"=>{"title"=>"Hello", "content"=>"Hello World", "category_id"=>"1", "profile_id"=>1}}

The previous format I tried was to wrap the data in a Post object, it was the same error.

I have tried to mock the id but I still received the error. I also tried removing the serializer, and I got a plain unprocessable entity error. Directly creating a post through console works though.
Tested on another project and I didn't receive any errors so it might not be the serializer's fault. However, I'm not sure where else to look in this case. Thanks in advance!

Edit: PostSerializer code as requested

class PostSerializer
  include FastJsonapi::ObjectSerializer
  belongs_to :profile
  attributes :id, :category_id, :title, :content
end
2

There are 2 answers

0
FSK-2563 On BEST ANSWER

The problem has been fixed.

The problem resides in the following line:

@post = Post.new(post_params)

In my question, I forgot to mention that I have tried the following:

@profile = current_user.profile
@post = @profile.post.new(post_params)

I got it mixed up with the test project I used, I apologise for the inconvenience. For some reason the following worked:

@post = current_user.profile.post.build(post_params)

Theoretically these two approach have no difference to my knowledge, so I'm not sure why this would solve the issue. I hope someone can explain it. Thank you :)

0
max On

The problem here is that you're passing the ActiveModel::Errors object returned by @post.errors to your PostSerializer which expects a model instance. As far as I know jsonapi-serializer does not have built in handling of validation errors.

Instead you want to create a special serializer for errors or just create the JSON response manually from the ActiveModel::Errors object. This is the example given in the json:api docs:

HTTP/1.1 422 Unprocessable Entity
Content-Type: application/vnd.api+json

{
  "errors": [
    {
      "source": { "pointer": "/data/attributes/firstName" },
      "title": "Invalid Attribute",
      "detail": "First name must contain at least three characters."
    },
    {
      "source": { "pointer": "/data/attributes/firstName" },
      "title": "Invalid Attribute",
      "detail": "First name must contain an emoji."
    }
  ]
}