How to pass object as JSON to a POST or PUT request in grails - rest

I am using restful service in grails. I have 2 classes Person
import grails.rest.Resource
#Resource(formats=['json', 'xml'])
class Person {
String name
Address address
static constraints = {
}
}
and Address as
import grails.rest.Resource
#Resource(formats=['json', 'xml'])
class Address {
String house
static constraints = {
}
}
and in bootstrap I could create new person entry as follows
new Person(name:"John" , address: new Address(house:"John Villa").save()).save();
but the problem is I want to do the same thing using a POST request with JSON data.
I set the UrlMappings.Groovy like
"/app/person"(resources: "person", includes: ['index', 'show', 'save', 'update', 'delete', 'create', 'patch'])
"/app/address"(resources: "address", includes: ['index', 'show', 'save', 'update', 'delete', 'create', 'patch'])
then I tried using POSTMAN rest client by sending a POST request to '/app/person' with JSON data
{
"name":"john" ,
"address": "{'house' :'sample address' }"
}
but it gives error 422 unprocessable entity.
How can I do the same using JSON ? I want to do both insertion and updation using POST and PUT methods.

The issue is with the JSON you are sending. While it's valid JSON it's not the correct representation for your resource. Your JSON should be:
{
"name":"john",
"address":
{
"house":"sample address"
}
}
As you can see from the above that the address property is actually a nested object and not a String like you are sending.

Moreover did you check guides on http://grails.github.io/grails-doc/latest/guide/webServices.html ?
Especially I would like you to check section:
grails.mime.types = [
…
json: ['application/json', 'text/json'],
…
xml: ['text/xml', 'application/xml']
]
Remember that when you process '/app/person' with PersonInstance, you in fact execute '/app/person/index/' with PersonInstance (so debug it's source if needed).
Also double check 'id' column in your classes.

Related

How to set idField in feathersVuex auth service

I have an issue that I couldn't resolve for a quite long time.
I'm making a shop using feathersJS as a backend api and Vue.js on the front and Mongodb. As I try to authenticate user on website, everything goes smoothly until "setUser" action fires and in auth service getters I get an error saying "Cannot read property 'idField' of undefined". I believe that I changed this property to "_id", wherever I could, but still this error occurs. Here are some screenshots, that may be helpful. This project is supposed to get me my first job in webDev so I would be eternally grateful for your support.
AddItem action in vuex,
setUser action in vuex
Feathers-client.js:
import feathers from '#feathersjs/feathers';
import socketio from '#feathersjs/socketio-client';
import auth from '#feathersjs/authentication-client';
import io from 'socket.io-client';
import { iff, discard } from 'feathers-hooks-common';
import feathersVuex from 'feathers-vuex';
const socket = io('http://localhost:3030', { transports: ['websocket'] });
const feathersClient = feathers()
.configure(socketio(socket))
.configure(auth({ storage: window.localStorage, debug: false }))
.hooks({
before: {
all: [
iff(
context => ['create', 'update', 'patch'].includes(context.method),
discard('__id', '__isTemp'),
),
],
},
});
export default feathersClient;
// Setting up feathers-vuex
const {
makeServicePlugin, makeAuthPlugin, BaseModel, models, FeathersVuex,
} = feathersVuex(
feathersClient,
{
idField: '_id', // Must match the id field in your database table/collection
whitelist: ['$regex', '$options'],
},
);
export {
makeAuthPlugin, makeServicePlugin, BaseModel, models, FeathersVuex,
};
auth service file:
import { makeAuthPlugin } from '../../feathers-client';
export default makeAuthPlugin({
userService: 'api/users',
entityIdField: '_id',
});
The issue here was the name of the service, which as a plugin in vuex was under a name of "users" not "api/users". The solution was to change in servicePlugin options nameStyle: "path" instead of "short"

ExtJS: Rest Proxy Post Data Failure

Hy,
I've a Problem by sending data via ExtJs Rest Proxy. When I POST Data I get the Exception
in Chrome: Uncaught TypeError: Cannot read property 'clientIdProperty' of undefined
in Firefox: TypeError: clientRecords[0] is undefined
My Store
Ext.define('Test.store.Test', {
extend: 'Ext.data.Store',
requires: [
'Test.model.test',
'Ext.data.proxy.Rest',
'Ext.data.reader.Json'
],
constructor: function(cfg) {
var me = this;
cfg = cfg || {};
me.callParent([Ext.apply({
storeId: 'Test',
model: 'Test.model.test',
proxy: {
type: 'rest',
url: '/resources/php/test.php',
reader: {
type: 'json'
}
}
}, cfg)]);
}
My Model
Ext.define('Test.model.test', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.field.Field'
],
fields: [
{
name: 'Test'
}
]
Is there a standard answer from Server?
I hope some one can Help me
Thx for Help
In your reader config, provide a 'root' property.
In ext 4.x it'll be like
reader: {
type: 'json',
root: 'root'
}
And in Ext 5.x, it'll be
reader: {
type: 'json',
rootProperty: 'root'
}
Here's what API doc says -
rootProperty : String The name of the property which contains the data
items corresponding to the Model(s) for which this Reader is
configured. For JSON reader it's a property name (or a dot-separated
list of property names if the root is nested). For XML reader it's a
CSS selector. For Array reader the root is not applicable since the
data is assumed to be a single-level array of arrays.
By default the natural root of the data will be used: the root JSON
array, the root XML element, or the array.
The data packet value for this property should be an empty array to
clear the data or show no data.
Defaults to: ''
For example, if the JSON response from the server is
{
"data": {
"Test": "TEST"
},
"someOtherField": "Some Value"
}
then, your rootProperty/ root will become -
rootProperty: 'data'
- Since data corresponds to your model

In Extjs5, erase() can't relate to destory api when the proxy type is rest

This is my viewController:
onRestDeleteClick: function(){
var ouType = Ext.create('MyApp.model.OuType',
{
id: 49,
ouTypeName: 'Lenlee',
entityName: 'Lenlee'
});
ouType.erase();
}
The model whose id is 49 exists in database.
This is the OuType model:
Ext.define('MyApp.model.OuType', {
extend: 'Ext.data.Model',
requires: [
'Ext.data.field.Field'
],
fields: [
{
name:'id'
},
{
name: 'ouTypeName'
},
{
name: 'entityName'
}
],
proxy:{
type: 'rest',
api: {
read: 'role/read',
update: 'role/update',
create: 'role/create',
destory: 'role/destory'
}
}
});
This is my server class:
#RequestMapping("/role")
#Controller("sysRoleContro")
public class SysRoleController {
…………
…………
#RequestMapping(value="/destory/{id}")
public void destoryOuType(HttpServletRequest request,
HttpServletResponse response, #PathVariable("id") Long id){
log.info("destory");
ouTypeRepository.delete(id);
log.info("end");
}
………
……
}
Now when i click the delete button, the request url is: http://localhost:7080/MyApp.model.OuType/49 404 Not Found.
The expected url is http://localhost:7080/CSQMS/role/destory/49
How can i delete the model?
Rest proxy is special in that that it does not CRUD operations to urls, as you set in api, but to HTTP verbs: GET, POST, PUT, DELETE, etc. So api config is most likely ignored. Configure the proxy this way:
proxy:{
type:'rest',
url:'/CSQMS/role'
}
If your server expects that CRUD operation verb is part of the URL you probably need a different proxy or you need to implement buildUrl method.
I want to say i'm so careless, i should write 'destroy' instead of 'destory'. MY GOD.

Ember-data store PUT request

Is there any way to include the 'has many' models in the 'put' request sent using ember data-store REST adapter?
You can have embedded records by defining them on the adapter
Comment = DS.Model.extend({
votes: DS.hasMany(Vote)
});
Adapter.map(Comment, {
votes: { embedded: 'always' }
});
https://github.com/emberjs/data/blob/master/packages/ember-data/tests/integration/embedded/embedded_dirtying_test.js#L53

Custom proxies on Stores and Models seems inconsistent (and does not work on Models)

Am using Extjs 4, and have created a custom Rest Proxy to handle communication with my Zend backend api.
(See post http://techfrere.blogspot.com/2011/08/linking-extjs4-to-zend-using-rest.html)
When using a Store to handle communication, I was using Ext.require to load the proxy, and then referenced the proxy on the type field and all was good and it loaded my data: as per:
Ext.require('App.utils.ZendRest');
...
proxy : {
type : 'zest', // My custom proxy alias
url : '/admin/user'
...
}
I then decided to try to use the proxy directly on a model... and no luck. The above logic does not work.
Problems
1. When referencing zest, it does not find the previously loaded ZendRest class (aliased to proxy.zest)
2. It tries to load the missing class from App.proxy.zest (which did not exist.)
So I tried moving my class to this location and renaming to what it seemed to want. No luck.
It loads the class, but still does not initialize the app... I get no errors anywhere so v difficult to figure out where the problem is after this...
For now it seems I will have to revert to using my Zend Rest proxy always via the Store.
Question is... has anyone else seen the behavior? Is it a bug, or am I missing something?
Thanks...
Using your proxy definition, I've managed to make it work.
I am not sure why it doesn't work for you. I have only moved ZendRest to Prj.proxy namespace and added requires: ['Prj.proxy.ZendRest'] to the model.
Code:
// controller/Primary.js
Ext.define('Prj.controller.Primary', {
extend: 'Ext.app.Controller',
stores: ['Articles'],
models: ['Article'],
views: ['article.Grid']
});
// model/Article.js
Ext.define('Prj.model.Article', {
extend: 'Ext.data.Model',
fields: [
'title', 'author', {
name: 'pubDate',
type: 'date'
}, 'link', 'description', 'content'
],
requires: ['Prj.proxy.ZendRest'],
proxy: {
type: 'zest',
url: 'feed-proxy.php'
}
});
// store/Articles.js
Ext.define('Prj.store.Articles', {
extend: 'Ext.data.Store',
autoLoad: true,
model: 'Prj.model.Article'
});
// proxy/ZendRest.js
Ext.define('Prj.proxy.ZendRest', {
extend: 'Ext.data.proxy.Ajax',
alias : 'proxy.zest',
appendId: true,
batchActions: false,
buildUrl: function(request) {
var me = this,
operation = request.operation,
records = operation.records || [],
record = records[0],
format = me.format,
reqParams = request.params,
url = me.getUrl(request),
id = record ? record.getId() : operation.id;
if (me.appendId && id) {
if (!url.match(/\/$/)) {
url += '/';
}
url += 'id/' + id;
}
if (format) {
reqParams['format'] = format;
}
/* <for example purpose> */
//request.url = url;
/* </for example purpose> */
return me.callParent(arguments);
}
}, function() {
Ext.apply(this.prototype, {
actionMethods: {
create : 'POST',
read : 'GET',
update : 'PUT',
destroy: 'DELETE'
},
/* <for example purpose> */
reader: {
type: 'xml',
record: 'item'
}
/* </for example purpose> */
});
});
Here is working sample, and here zipped code.