Ember-cli , how do i change rest call on fly in the rest adapter - rest

Im working on ember-cli, how do i change rest call on fly in the rest adapter. If i use path params not query params?for example:
export default DS.RESTAdapter.extend({
namespace:'res/v1/users/id',
pathForType: function() {
return Ember.String.underscore("friends");},});
Based on the user selection from dropdown we get the "id", using the id I need to get user friends from the database.
Could you please suggest a better way to do. My aapplication supports pathparams not the query params

To customize the URL, override the buildURL method in your adapter.
The tricky part is to access related records from the adapter. For example, you request friends for a given user. You work in a friend adapter, but you need to know the user's id to include it in the URL.
For that purpose, use the record property on the snapshot argument of the buildURL method.
Alternatively, you might want to override some of buildURL's underlying methods such as urlForFindQuery, depending on how you request your model from the store. With a find.query(), you will retrieve the id of the user from the query.
If this does not help you, please respond with the way you're trying to fetch friends from the store.

I have created a variable in enviroment.js 'userId'. When ever i select a user
i set config.userId in the controller to the corresponding Id.
config.userId=this.get('selectedUser');
In pathforType of adapter I used this varible
pathForType: function() {
return Ember.String.underscore(config.userId+"/friends");
}
you just need to add an import statement
import config from '../config/environment';
Please suggest me if anyone get to know better way. Thanks all for your responses

buildURL() only takes the type imo. so you have to pass some more jazz.
i did something along the lines of the following in the application adapter
$ ember generate adapter application
app/adapters/application.js
import DS from 'ember-data';
export default DS.RESTAdapter.extend({
findQuery: function(store, type, query) {
var urlQuery = query.theshityouwant;
var reply = this.ajax(this.buildURL(type.typeKey + '/' + urlQuery), 'GET', { headers: all});
return reply;
},
})
});

Related

Add a subpanel record to a SugarCRM account through REST API

Question: How do I create a subpanel record through the SugarCRM rest api endpoint for accounts?
Steps taken so far:
I've added a new package called, "transactionHistory" with a module named, "InvoiceHistory" using the SugarCRM studio.
I added a One to Many relationship to the Accounts module using studio.
I'm using NetSuite to push new invoices to the new module's record via the subpanel "create" option. Here's the code I'm using:
function createSugarTransaction(transaction, token) {
var url = 'https://crm.techsoft3d.com/rest/v10/Accounts/' + transaction.customer;
var headers = {
"Content-Type": "application/json",
"OAuth-Token": token
};
var now = (new Date()).toISOString();
var body = {transactionHistory_InvoiceHistory:
{
create: [{
name: transaction.docId,
transaction_date_c: transaction.date,
invoice_status_c: transaction.status,
due_date_c: transaction.duedate,
total_amount_c: transaction.total,
amount_due_c: transaction.remaining,
start_date_c: transaction.startdate,
end_date_c: transaction.enddate
}]
}
};
var response = nlapiRequestURL(url, JSON.stringify(body), headers, 'PUT');
return response;
}
The transaction object has been validated and the json object within the create: [] array has matching sugar fields (key) with the corresponding transaction object values.
When making the API call to sugar I'm successfully authenticated and have access to the custom module and accounts - so no problem there. However, when the call is returned to response it's showing the following error:
{"error":"no_method","error_message":"Could not find a route with 1 elements"}
I'm unsure of what else is needed in order for the record to be created. According to sugar's help documentation and developer community this should work. I'm using the basic information provided by sugarcrm support portal:
http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/API/Web_Services/Examples/v10/module_POST/
According to other blog posts within the developer community, it should be as simple as adding the subpanel name, followed by an array of fields under the "create" object... similar to this:
var requestBody = { package_module:create[{name:value}]};
My initial thinking of what's wrong is:
1. my package_module name isn't correct, but I'm unable to find it anywhere within the applicaiton or help documentation.
2. the request body isn't formatted properly, even though it's structure was copied from this article https://developer.sugarcrm.com/2014/02/28/sugarcrm-cookbook2/
Any help would be appreciated.
try the createRelatedRecord api endpoint
type {sugarurl}/rest/v10/help to see a list of endpoints to look through, most of which have documentation and examples
https://crm.techsoft3d.com/rest/v10/help
your API url should have the name of the link (relationship) you want, in addition to the values in the POST payload
https://crm.techsoft3d.com/rest/v10/Accounts/{transaction.customer}/link/accounts_transactionhistory (or whatever your link's name is)
per the documentation for this endpoint, you just specify the field values in the payload
{
"first_name":"Bill",
"last_name":"Edwards"
}

Meteor Method to send a public MongoDB document without publishing everything

new to meteor and mongo.
I have some JSON stored in mongo that I want to publicly expose via an obfuscated token without using something like:
//app/models/stuff.js
Stuff = new Mongo.Collection("stuff");
Meteor.publish("stuff", function (){
return Stuff.find();
});
//additionally, the client-side subscription
I only want to expose the files that the client directly requests via a URL routing parameter or some sort of client side identifier (like a textfield where you can type the code/token in)
e.g., http://website.com/view/abcdefghijklmnop
Anyone with knowledge of the link can type it in, and get the file. However, there should be no way to just get every file without being given every token.
I was wondering if this was the best way to accomplish the task:
//app/server/stuff.js
Meteor.methods({
getStuff: getStuff
});
function getStuff(stuffId) {
var result = Stuff.find({_id: stuffId});
return result;
}
then
//app/client/stuff.js
var json = Meteor.call('getStuff', 'abcdefghijklmnop');
Why not just publish the requested document?
Meteor.publish('stuff', function (id){
check(id, String);
return Stuff.find(id);
});

Sail.js - routing to methods, custom policies & PATCH method

I have a few questions that I couldn't find answers anywhere online.
Does sails.js framework support HTTP PATCH method? If not - does anyone know if there is a planned feature in the future?
By default if I create method in a controller it is accessible with GET request is it the routes.js file where I need to specify that method is accessible only via POST or other type of methods?
How would you create a policy that would allow to change protected fields on entity only for specific rights having users. I.e: user that created entity can change "name", "description" fields but would not be able to change "comments" array unless user is ADMIN?
How would you add a custom header to "find" method which specifies how many items there are in database? I.e.: I have /api/posts/ and I do query for finding specific items {skip: 20; limit: 20} I would like to get response with those items and total count of items that would match query without SKIP and LIMIT modifiers. One thing that comes to my mind is that a policy that adds that that custom header would be a good choice but maybe there is a better one.
Is there any way to write a middle-ware that would be executed just before sending response to the client. I.e.: I just want to filter output JSON not to containt some values or add my own without touching the controller method.
Thank you in advance
I can help with 2 and 5. In my own experience, here is what I have done:
2) I usually just check req.method in the controller. If it's not a method I want to support, I respond with a 404 page. For example:
module.exports = {
myAction: function(req, res){
if (req.method != 'POST')
return res.notFound();
// Desired controller action logic here
}
}
5) I create services in api/services when I want to do this. You define functions in a service that accept callbacks as arguments so that you can then send your response from the controller after the service function finishes executing. You can access any service by the name of the file. For example, if I had MyService.js in api/services, and I needed it to work with the request body, I would add a function to it like this:
exports.myServiceFunction = function(requestBody, callback){
// Work with the request body and data access here to create
// data to give back to the controller
callback(data);
};
Then, I can use this service from the controller like so:
module.exports = {
myAction: function(req, res){
MyService.myServiceFunction(req.body, function(data){
res.json(data);
});
}
}
In your case, the data that the service sends back to the controller through the callback would be the filtered JSON.
I'm sorry I can't answer your other questions, but I hope this helps a bit. I'm still new to Sails.js and am constantly learning new things, so others might have better suggestions. Still, I hope I have answered two of your questions.

Angular JS: Full example of GET/POST/DELETE/PUT client for a REST/CRUD backend?

I've implemented a REST/CRUD backend by following this article as an example: http://coenraets.org/blog/2012/10/creating-a-rest-api-using-node-js-express-and-mongodb/ . I have MongoDB running locally, I'm not using MongoLabs.
I've followed the Google tutorial that uses ngResource and a Factory pattern and I have query (GET all items), get an item (GET), create an item (POST), and delete an item (DELETE) working. I'm having difficulty implementing PUT the way the backend API wants it -- a PUT to a URL that includes the id (.../foo/) and also includes the updated data.
I have this bit of code to define my services:
angular.module('realmenServices', ['ngResource']).
factory('RealMen', function($resource){
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT'},
remove: {method:'DELETE'}
});
I call the method from this controller code:
$scope.change = function() {
RealMen.update({entryId: $scope.entryId}, function() {
$location.path('/');
});
}
but when I call the update function, the URL does not include the ID value: it's only "/realmen", not "/realmen/ID".
I've tried various solutions involving adding a "RealMen.prototype.update", but still cannot get the entryId to show up on the URL. (It also looks like I'll have to build the JSON holding just the DB field values myself -- the POST operation does it for me automatically when creating a new entry, but there doesn't seem to be a data structure that only contains the field values when I'm viewing/editing a single entry).
Is there an example client app that uses all four verbs in the expected RESTful way?
I've also seen references to Restangular and another solution that overrides $save so that it can issue either a POST or PUT (http://kirkbushell.me/angular-js-using-ng-resource-in-a-more-restful-manner/). This technology seems to be changing so rapidly that there doesn't seem to be a good reference solution that folks can use as an example.
I'm the creator of Restangular.
You can take a look at this CRUD example to see how you can PUT/POST/GET elements without all that URL configuration and $resource configuration that you need to do. Besides it, you can then use nested resources without any configuration :).
Check out this plunkr example:
http://plnkr.co/edit/d6yDka?p=preview
You could also see the README and check the documentation here https://github.com/mgonto/restangular
If you need some feature that's not there, just create an issue. I usually add features asked within a week, as I also use this library for all my AngularJS projects :)
Hope it helps!
Because your update uses PUT method, {entryId: $scope.entryId} is considered as data, to tell angular generate from the PUT data, you need to add params: {entryId: '#entryId'} when you define your update, which means
return $resource('http://localhost\\:3000/realmen/:entryId', {}, {
query: {method:'GET', params:{entryId:''}, isArray:true},
post: {method:'POST'},
update: {method:'PUT', params: {entryId: '#entryId'}},
remove: {method:'DELETE'}
});
Fix: Was missing a closing curly brace on the update line.
You can implement this way
$resource('http://localhost\\:3000/realmen/:entryId', {entryId: '#entryId'}, {
UPDATE: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId' },
ACTION: {method: 'PUT', url: 'http://localhost\\:3000/realmen/:entryId/action' }
})
RealMen.query() //GET /realmen/
RealMen.save({entryId: 1},{post data}) // POST /realmen/1
RealMen.delete({entryId: 1}) //DELETE /realmen/1
//any optional method
RealMen.UPDATE({entryId:1}, {post data}) // PUT /realmen/1
//query string
RealMen.query({name:'john'}) //GET /realmen?name=john
Documentation:
https://docs.angularjs.org/api/ngResource/service/$resource
Hope it helps

Tastypie build_filters access tp request.user

Is there any way to access the user that initiated the request in build_filters override in tastypie.
I want to use the logged in user to give context to one of the filters for example filter contains the word Home and i want to use this as a lookup to the requesting users locations to find their home address.
If build filters took the request as an argument this would be easy as i could simply call
request.user.get_profile().userlocation_set.get(name_iexact=filters['location'])
Is there anyway to force the user into the list of filters or alternatively enrich get parameters before they are passed to build_filters.
There still isn't a great method for this. I'm currently overriding obj_get_list like so, so that I can manually pass the bundle object to build_filters:
def obj_get_list(self, bundle, **kwargs):
filters = {}
if hasattr(bundle.request, 'GET'):
filters = bundle.request.GET.copy()
filters.update(kwargs)
applicable_filters = self.build_filters(filters=filters, bundle=bundle)
try:
objects = self.apply_filters(bundle.request, applicable_filters)
return self.authorized_read_list(objects, bundle)
except ValueError:
raise BadRequest("Invalid resource lookup data provided (mismatched type).")
There is currently an open pull request for this change:
https://github.com/toastdriven/django-tastypie/pull/901
I haven't found a way to do that. I generally 'cheat' by adding the code into apply_authorization_limits where the session is available.