cloudcreativity / laravel-json-api

JSON API (jsonapi.org) package for Laravel applications.
http://laravel-json-api.readthedocs.io/en/latest/
Apache License 2.0
778 stars 109 forks source link

Override model save method #616

Closed ale1981 closed 3 years ago

ale1981 commented 3 years ago

I need to use a stored procedure to save records to the database, which method should I override and how do I access the attributes from the POST route?

lindyhopchris commented 3 years ago

You'll need to look at the adapter class. The entry points are the create() and update() methods. However if you look at the implementation in the parent classes, you might find there's an internal method that you can override depending on your use case. E.g. both those methods end up calling persist() internally.

The JSON document is passed to those methods so you have access to it. If you need anything else from the request, use Laravel's request() helper.

ale1981 commented 3 years ago

Hi @lindyhopchris, thanks for the reply.

Looking at the adapter class, persist() just calls the model save()?

lindyhopchris commented 3 years ago

Yes, but it's in there as a separate method so developers can overload it if required.

ale1981 commented 3 years ago

Yes. In the persist() method I am struggling to get the attributes from the $record as they seem to be empty?

Does anything need to be returned from the persist() method, once it runs I get an empty record returned by the API.

lindyhopchris commented 3 years ago

The attributes are filled into the model by that point. So you should be able to get them from the record. If you're not, you'll need to investigate what about your set up is causing the attributes to not be filled. For instance, they need to be fillable on the model.

ale1981 commented 3 years ago

Thanks, it seems I needed to alter $guarded in the Adapter.

I now have the stored procedure working and the record is being created in the database, however the API response shows an empty record, what could be causing that?

lindyhopchris commented 3 years ago

Don't know - you'd need to debug. By empty, if you mean the data member is null then it isn't being returned from somewhere. If you mean the attributes are empty, then that might be down to your persistence implementation. Can't really say for sure, depends on your implementation which is why you'd need to debug.

ale1981 commented 3 years ago

I am struggling to debug.

The data member is populated, just all the attributes are empty, it's like the newly created record hasn't been loaded in the response but I have no idea where this is set.

lindyhopchris commented 3 years ago

The newly created record is returned from the create method on the adapter. It obviously works normally, so my guess would be that it's related to whatever this other stored procedure method is that you have? You'd need to make sure the correctly persisted model is returned from the adapter's create() method.

Sorry to not be more help - it's impossible for me to provide detailed guidance as I don't know what you've changed and don't have access to your application to debug.

lindyhopchris commented 3 years ago

The created record is obtained in the controller here: https://github.com/cloudcreativity/laravel-json-api/blob/4fb96331ae6c96cb172678cf4cda530e983d5694/src/Http/Controllers/JsonApiController.php#L434

That's getting it via the store, but all the store does is call the method on the correct adapter. So you need to make sure a fully completed and persisted model is returned from your adapter's create() method.

ale1981 commented 3 years ago

I appreciate your help.

I tried this from a different angle and left the JSON API methods alone and tried to override the insertAndSetId() method on the Laravel model, all that does as far as I can tell is insert in to the DB and set the returned ID, which I did, but get the same result, the returned model has empty attributes.

Is there a requirement to set every attribute via the data object when calling the POST route or can some be omitted?

lindyhopchris commented 3 years ago

Have no idea what you mean by the data object? Obviously the attributes would need to be set on the model, otherwise they won't appear when your schema serializes the attributes in its getAttribute() method.

Are the attributes fillable on your model? Have you debugged what happens when the adapter fills them?

Does the model have the attributes set when it is being serialized in the schema's getAttribute() method? Is the model in that method the one that has been saved to the database?

I really can't help much more I'm afraid. The package obviously works, it's used in production applications. So not sure what is going on with yours - and without access to the application, I can't really help. (To be clear, I'm not asking for access to the application - it's more that I'm reliant on what you can debug.)

ale1981 commented 3 years ago

Thanks for your help. I managed to debug and get this working.

The issue was the $attributes names being populated by the model in uppercase but the adapter was expecting them in lowercase, hence why they were null.

One last question...! Is there a way to manually raise an error in the API response, the stored procedure can return some different errors and wondered if I can display these to the user?

ale1981 commented 3 years ago

Please ignore, I found the following...

https://laravel-json-api.readthedocs.io/en/latest/features/errors/

lindyhopchris commented 3 years ago

Great, glad you got it sorted.