Sencha Model.save sends /0.json to server - ruby-on-rails

I've got the following code, which supposed to create a new item. Proxy type is REST.
var inst = Ext.ModelMgr.create({
title: values.title
}, "EntriesModel");
inst.save({
success: function(model) {
console.log(model);
}
});
After save(), I see that request is sent to http://localhost:3000/entries/0.json, while I assume it should have been sent to http://localhost:3000/entries
Entries model looks like this
Ext.regModel("EntriesModel", {
fields: [
{name: "id", type: "int"},
{name: "title", type: "string"},
{name: "list_id", type:"int"},
{name: "bought", type: "boolean"},
],
proxy: {
type: 'rest',
url: '/entries',
format: 'json',
noCache: true,
reader: {
type: 'json',
root: 'data'
},
writer: {
type: 'json'
},
listeners: {
exception: function (proxy, response, operation) {
console.log(proxy, response, operation);
}
}
}
});
Backend is Rails.

Look at this, how building a link for a Rest Proxy:
buildUrl: function(request) {
var records = request.operation.records || [],
record = records[0],
format = this.format,
url = request.url || this.url;
if (this.appendId && record) {
if (!url.match(/\/$/)) {
url += '/';
}
url += record.getId();
}
if (format) {
if (!url.match(/\.$/)) {
url += '.';
}
url += format;
}
request.url = url;
return Ext.data.RestProxy.superclass.buildUrl.apply(this, arguments);
}
Override this to provide further customizations, but remember to call the superclass buildUrl

Try to read this http://dev.sencha.com/deploy/touch/docs/?class=Ext.data.RestProxy
and example:
new Ext.data.RestProxy({
url: '/users',
format: 'json'
});
// Collection url: /users.json
// Instance url : /users/123.json

Related

Convert API Gateway Cloudformation template to Swagger file

There is an existing API described in a Coludformation template. Now I want to document the API using Swagger. Is there a way to parse the Cloudformation template to create the swagger.yaml specification file? I would like to avoid writing the API a second time, if possible.
Note: I am aware that you can define your API using Swagger, then import the API configuration in your Cloudformation template. This is not what I need. The Cloudformation already exists and will not be changed. Hence, I need the opposite: a Swagger configuration file based on an existing Cloudformation template.
There is no way to convert the template to a swagger file that I know about. But if you are looking for a way to keep service-spec in one place only (template) and you have it deployed, you can take swagger or OAS file from the stage (so to do it you must have a stage as well) in two ways at least:
By Web console. Use Amazon API Gateway->
APIs->Your API->Stages>Your Stage -> Export tab. See the picture: exporting Swagger or OAS as a file by Web console
aws apigateway get-export ... Here is an example:
aws apigateway get-export --rest-api-id ${API_ID} --stage-name ${STAGE_NAME} --export-type swagger swagger.json
I just made this, it is not setup for perfect plug/play, but will give you an idea what you need to adjust to get it working (also need to make sure you CF template is setup so it has the needed info, on mine I had to add some missing requestParams I was missing, also use this site to test your results from this code to see it works with swagger):
const yaml = require('js-yaml');
const fs = require('fs');
// Get document, or throw exception on error
try {
// loads file from local
const inputStr = fs.readFileSync('../template.yaml', { encoding: 'UTF-8' });
// creating a schema to handle custom tags (cloud formation) which then js-yaml can handle when parsing
const CF_SCHEMA = yaml.DEFAULT_SCHEMA.extend([
new yaml.Type('!ImportValue', {
kind: 'scalar',
construct: function (data) {
return { 'Fn::ImportValue': data };
},
}),
new yaml.Type('!Ref', {
kind: 'scalar',
construct: function (data) {
return { Ref: data };
},
}),
new yaml.Type('!Equals', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::Equals': data };
},
}),
new yaml.Type('!Not', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::Not': data };
},
}),
new yaml.Type('!Sub', {
kind: 'scalar',
construct: function (data) {
return { 'Fn::Sub': data };
},
}),
new yaml.Type('!If', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::If': data };
},
}),
new yaml.Type('!Join', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::Join': data };
},
}),
new yaml.Type('!Select', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::Select': data };
},
}),
new yaml.Type('!FindInMap', {
kind: 'sequence',
construct: function (data) {
return { 'Fn::FindInMap': data };
},
}),
new yaml.Type('!GetAtt', {
kind: 'scalar',
construct: function (data) {
return { 'Fn::GetAtt': data };
},
}),
new yaml.Type('!GetAZs', {
kind: 'scalar',
construct: function (data) {
return { 'Fn::GetAZs': data };
},
}),
new yaml.Type('!Base64', {
kind: 'mapping',
construct: function (data) {
return { 'Fn::Base64': data };
},
}),
]);
const input = yaml.load(inputStr, { schema: CF_SCHEMA });
// now that we have our AWS yaml copied and formatted into an object, lets pluck what we need to match up with the swagger.yaml format
const rawResources = input.Resources;
let guts = [];
// if an object does not contain a properties.path object then we need to remove it as a possible api to map for swagger
for (let i in rawResources) {
if (rawResources[i].Properties.Events) {
for (let key in rawResources[i].Properties.Events) {
// console.log(i, rawResources[i]);
if (rawResources[i].Properties.Events[key].Properties.Path) {
let tempResource = rawResources[i].Properties.Events[key].Properties;
tempResource.Name = key;
guts.push(tempResource);
}
}
}
} // console.log(guts);
const defaultResponses = {
'200': {
description: 'successful operation',
},
'400': {
description: 'Invalid ID supplied',
},
};
const formattedGuts = guts.map(function (x) {
if (x.RequestParameters) {
if (
Object.keys(x.RequestParameters[0])[0].includes('path') &&
x.RequestParameters.length > 1
) {
return {
[x.Path]: {
[x.Method]: {
tags: [x.RestApiId.Ref],
summary: x.Name,
parameters: [
{
name: Object.keys(x.RequestParameters[0])[0].split('method.request.path.')[1],
in: 'path',
type: 'string',
required: Object.values(x.RequestParameters[0])[0].Required,
},
{
name: Object.keys(x.RequestParameters[1])[0].split('method.request.path.')[1],
in: 'path',
type: 'string',
required: Object.values(x.RequestParameters[1])[0].Required,
},
],
responses: defaultResponses,
},
},
};
} else if (Object.keys(x.RequestParameters[0])[0].includes('path')) {
return {
[x.Path]: {
[x.Method]: {
tags: [x.RestApiId.Ref],
summary: x.Name,
parameters: [
{
name: Object.keys(x.RequestParameters[0])[0].split('method.request.path.')[1],
in: 'path',
type: 'string',
required: Object.values(x.RequestParameters[0])[0].Required,
},
],
responses: defaultResponses,
},
},
};
} else if (Object.keys(x.RequestParameters[0])[0].includes('querystring')) {
return {
[x.Path]: {
[x.Method]: {
tags: [x.RestApiId.Ref],
summary: x.Name,
parameters: [
{
name: Object.keys(x.RequestParameters[0])[0].split(
'method.request.querystring.'
)[1],
in: 'query',
type: 'string',
required: Object.values(x.RequestParameters[0])[0].Required,
},
],
responses: defaultResponses,
},
},
};
}
}
return {
[x.Path]: {
[x.Method]: {
tags: [x.RestApiId.Ref],
summary: x.Name,
responses: defaultResponses,
},
},
};
});
const swaggerYaml = yaml.dump(
{
swagger: '2.0',
info: {
description: '',
version: '1.0.0',
title: '',
},
paths: Object.assign({}, ...formattedGuts),
},
{ noRefs: true }
); // need to keep noRefs as true, otherwise you will see "*ref_0" instead of the response obj
// console.log(swaggerYaml);
fs.writeFile('../swagger.yaml', swaggerYaml, 'utf8', function (err) {
if (err) return console.log(err);
});
} catch (e) {
console.log(e);
console.log('error above');
}

My Kendo grid is not populating with JSON object returned from Controller

I am writing an MVC application that is storing certain information in session variables. I am able to populate a list I have in my repo class without a problem. The issue I am having is when I click on my search Client controller it just gives me a JSON object but does not populate my Kendo Grid.
This is my datasource:
var clientSearch = new kendo.data.DataSource({
transport: {
read: {
url: "SearchClient",
contentType: "application/json; charset=utf-8",
dataType: "json"
},
create: {
url: "ClientInformation",
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST"
},
parameterMap: function (data, operator) {
if (operator != "read")
return JSON.stringify(viewModel);
}
},
schema: {
model: {
id: "clientName",
}
}
});
This is my Grid:
$("#grid").kendoGrid({
dataSource: clientSearch,
columns: [{
field: "clientName",
title: "Client Name",
},
{
field: "clientNumber",
title: "Client Number",
},
{
field: "clientType",
title: "Client Type",
}]
})
This is my controller that is returning my JSON object:
[HttpGet]
public ActionResult SearchClient()
{
HttpSessionStateBase session = HttpContext.Session;
Repo repo = new Repo(session);
var result = repo.GetClient();
return Json(new
{
list = result,
count = result.Count
}, JsonRequestBehavior.AllowGet);
}
You need to specify your fields in the schema of data source object:
var clientSearch = new kendo.data.DataSource({
transport: {
read: {
url: "SearchClient",
contentType: "application/json; charset=utf-8",
dataType: "json"
},
create: {
url: "ClientInformation",
contentType: "application/json; charset=utf-8",
dataType: "json",
type: "POST"
},
parameterMap: function (data, operator) {
if (operator != "read")
return JSON.stringify(viewModel);
}
},
schema: {
model: {
id: "clientName",
fields: {
ID: { editable: false },
clientName: { editable: false },
clientNumber: { editable: false },
clientType: { editable: false }
}
}
});
Kendo.Mvc expects DataSourceRequest and DataSourceResult when binding grid as such:
public ActionResult SearchClient([DataSourceRequest] DataSourceRequest request)
{
HttpSessionStateBase session = HttpContext.Session;
Repo repo = new Repo(session);
var result = repo.GetClient();
return Json(new
{
list = result.ToList().ToDataSourceResult(request, ModelState)
}, "application/json", JsonRequestBehavior.AllowGet);
}

Data is getting but not populating in kendo grid using angular js

I am able to get the data from database but not populating in gridview.
here is my code below:
<div ng-app="app" ng-controller="MyCtrl">
<div kendo-grid k-options="gridOptions" k-rebind="gridOptions" k-pageable='{ "pageSize": 2, "refresh": true, "pageSizes": true }'></div>
</div>
<script>
angular.module("app", ["kendo.directives"]).controller("MyCtrl", function ($scope, $http) {
$scope.gridOptions = {
columns: [{ field: "EmployeeKey" }, { field: "FirstName" }],
dataSource: {
//schema: {
// data: "d"
//},
type: "jsonp",
transport: {
read: function (e) {
$http({ method: 'GET', url: '/Employee/Employee_Read' }).
success(function (data, status, headers, config) {
// alert('Sucess')
//debugger;
e.success(data)
}).
error(function (data, status, headers, config) {
alert('something went wrong')
console.log(status);
});
}
},
//pageSize: 5
}
}
});
</script>
and this is the controller page where i am getting data
public ActionResult Employee_Read ([DataSourceRequest] DataSourceRequest request )
{
//IQueryable<IEmployeeRepositary> employeeRep = employeeRepositary.Employees;
return Json(employeeRepositary.Employees.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}
so after running my application i am checking through debugger this line
"e.success(data)" so in mouse hove i am getting the total records fetched from database. but not populating in gridview it is still showing blank.
please help me out from here.
Because you are returning collection which wrapped with DataSourceResult method.
return Json(employeeRepositary.Employees.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
instead of just its collection
return Json(employeeRepositary.Employees, JsonRequestBehavior.AllowGet);
You need to define your data source schema, please try this schema setup
schema: {
data: "Data",
errors: "Errors",
total: "Total",
model: {
id: "Id",
fields: {
Id: { editable: false, defaultValue: 0 },
//the rest field definition
}
}
}
and you can change your transport's read to something like this
read: {
type: "POST",
url: "/Employee/Employee_Read",
dataType: "json",
contentType: "application/json"
}
your final code should be like this
$scope.gridOptions = {
columns: [{ field: "EmployeeKey" }, { field: "FirstName" }],
dataSource: {
transport: {
read: {
type: "POST",
url: "/Employee/Employee_Read",
dataType: "json",
contentType: "application/json"
},
parameterMap: function(options, operation) {
return JSON.stringify(options);
}
},
pageSize: 5,
schema: {
data: "Data",
errors: "Errors",
total: "Total",
model: {
id: "EmployeeKey",
fields: {
EmployeeKey: { editable: false, defaultValue: 0 },
FirstName: {type: "string", validation: { required: true }}
}
}
}
}
}
and your controller like this
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Employee_Read ([DataSourceRequest] DataSourceRequest request )
{
var employees = employeeRepositary.Employees;
return Json(employees.ToDataSourceResult(request), JsonRequestBehavior.AllowGet);
}

Sencha touch customise rest proxy url

I need to pass addition param to jersey server. But how do I submit my url like ..get/{param1}/{param2}/{param3}
Here is my js file
Ext.define('bluebutton.view.BlueButton.testing', {
extend: 'Ext.form.Panel',
xtype: 'testing',
requires: [
'bluebutton.view.BlueButton.TransactionList',
'bluebutton.view.BlueButton.MemberPopUp',
'bluebutton.view.BlueButton.MemberDetail',
'bluebutton.store.BlueButton.MemberList',
],
config: {
id:'register',
items :[
{
xtype: 'textfield',
name: 'name',
label: 'Name'
},
{
xtype: 'emailfield',
name: 'email',
label: 'Email'
},
{
xtype: 'button',
text: 'Send',
handler: function(button) {
var form = Ext.getCmp('register');
values = form.getValues();
// Select record
//If load data , restful will using "get", url will be /users/1
var User = Ext.ModelMgr.getModel('bluebutton.model.BlueButton.MemberList');
User.load(123,
{
success: function(user) {
alert(user.get('fullName'));
}
}
);
}
}
],
}
});
Model.js
Ext.define('bluebutton.model.BlueButton.MemberList', {
extend: 'Ext.data.Model',
config: {
idProperty: 'memberModel',
fields: [
{ name: 'fullName' },
{ name: 'singer' },
],
proxy: {
type: 'rest',
url: 'http://localhost:8080/RESTFulExample/rest/json/metallica/get',
reader: 'json',
actionMethods: {
create: 'GET',
read: 'POST',
update: 'PUT',
destroy: 'DELETE'
},
reader: {
type: 'json',
},
writer: {
type: 'json',
},
}
}
});
But now I only able to pass my url like ..get/123 Please guide me some solution.Thanks
2 things coming to my mind, First do not write proxy inside model definition, instead set it in initialize function of store where you can look at config data and create url on its basis. e.g.
initialize: function() {
var myId = this.config.uid;
this.setProxy({
type: 'rest',
url: 'http://localhost:8080/RESTFulExample/rest/json/metallica/get/'+myId,
reader: 'json',
actionMethods: {
create: 'GET',
read: 'POST',
update: 'PUT',
destroy: 'DELETE'
},
reader: {
type: 'json',
},
writer: {
type: 'json',
},
});
}
and you can pass id to load when you create the store like this:
var memberStore = Ext.create('bluebutton.store.BlueButton.MemberList', {
uid : 123
});
2nd way could be writing your own proxy extending Ext.data.proxy.Rest and implementing buildUrl such that it checks for data and append it to url. e.g.
buildUrl: function(request) {
var me = this,
url = me.callParent(arguments);
if(!Ext.isEmpty(someData)){
url = Ext.urlAppend(url, "data="+someData);
}
return url;
}
I hope it helps.
EDIT
Sample code for custom proxy which I have used in past to append some token to every request
Ext.define('myapp.proxy.CustomJsonpProxy', {
extend: 'Ext.data.proxy.JsonP',
alias: 'proxy.customjsonpproxy',
buildUrl: function(request) {
var me = this,
url = me.callParent(arguments);
if(!Ext.isEmpty(loggedInUserToken)){
url = Ext.urlAppend(url, "token="+loggedInUserToken);
}
return url;
}
});
the below code worked for me....to set a param to an url
myStore.getProxy().getApi().read = myStore.getProxy().getApi().read + param;

Sencha touch one store instance for multiple stores

So I have two stores that use the exact same model, they are exactly the same in every way (except for their names of course). I want two different stores.
app.stores.newsFeed = new Ext.data.Store({
model: 'app.models.feedData',
proxy: {
type: 'scripttag',
url: 'http://query.yahooapis.com/v1/public/yql',
extraParams: {
format: 'json'
},
reader: {
root: 'query.results.item'
}
}
});
app.stores.eventsFeed = new Ext.data.Store({
model: 'app.models.feedData',
proxy: {
type: 'scripttag',
url: 'http://query.yahooapis.com/v1/public/yql',
extraParams: {
format: 'json'
},
reader: {
root: 'query.results.item'
}
}
});
My question is can I save space by getting rid of code and use only one store instance so I don't have to re-declare another new Ext.data.Store again?
something like:
store = new Ext.data.Store(...);
app.stores.newsFeed = store;
app.stores.eventsFeed = store;
I tried this before but both were assigned to the same store so when one was changed so was the other.
Just extend extJS component and you can get fast instances of your component:
MyStore = Ext.extend(Ext.data.Store, {
constructor : function(config) {
config = Ext.apply({
model: 'app.models.feedData',
proxy: {
type: 'scripttag',
url: 'http://query.yahooapis.com/v1/public/yql',
extraParams: {
format: 'json'
},
reader: {
root: 'query.results.item'
}
}
}, config);
MyStore.superclass.constructor.call(this, config);
},
onDestroy : function(config) {
MyStore.superclass.onDestroy.apply(this, arguments);
}
});
And create as much independent instanses as you want:
app.stores.newsFeed = Ext.create(MyStore, {});
app.stores.eventsFeed = Ext.create(MyStore, {});

Resources