Giter VIP home page Giter VIP logo

napp.alloy.adapter.restapi's Introduction

napp.alloy.adapter.restapi

RestAPI Sync Adapter for Titanium Alloy Framework.

Response Codes

The adapter has been designed with the following structure.

  • 200: The request was successful.
  • 201: The resource was successfully created.
  • 204: The request was successful, but we did not send any content back.
  • 304: The request was not modified.
  • 400: The request failed due to an application error, such as a validation error.
  • 401: An API key was either not sent or invalid.
  • 403: The resource does not belong to the authenticated user and is forbidden.
  • 404: The resource was not found.
  • 500: A server error occurred.

How To Use

Download restapi.js to PROJECT_FOLDER/app/assets/alloy/sync/ or use NPM thanks to appc-npm:

npm install alloy-sync-restapi --save

Add the following to your model in PROJECT_FOLDER/app/models/.

exports.definition = {
	config: {
		"URL": "http://example.com/api/modelname",
		//"debug": 1,
		"adapter": {
			"type": "restapi",
			"collection_name": "MyCollection",
			"idAttribute": "id"
		},
		"headers": { // your custom headers
            "Accept": "application/vnd.stackmob+json; version=0",
	        "X-StackMob-API-Key": "your-stackmob-key"
        },
        "parentNode": "news.domestic" //your root node
	},		
	extendModel: function(Model) {		
		_.extend(Model.prototype, {});
		return Model;
	},
	extendCollection: function(Collection) {		
		_.extend(Collection.prototype, {});
		return Collection;
	}		
}

Use the debug property in the above example to get logs printed with server response to debug your usage of the restapi adapter.

Lets see this in action

In your Alloy controller, do would use the REST API adapter like this:

var collection = Alloy.createCollection("MyCollection"); //or model
//the fetch method is an async call to the remote REST API.
collection.fetch({
	success : function(){
		_.each(collection.models, function(element, index, list){
			// We are looping through the returned models from the remote REST API
			// Implement your custom logic here
		});
	},
	error : function(){
		Ti.API.error("hmm - this is not good!");
	}
});

Another example is that,

// This is the handle for the item
var model = Alloy.createModel("MyCollection");

var params = {
    field1: "some field",
    fied2: "another field"
};

//the fetch method is an async call to the remote REST API.
model.save(params, {
    success : function(model) {
        Ti.API.log("Yay! Success!");
        Ti.API.log(model);
    },
    error : function(err) {
        Ti.API.error("hmm - this is not good!");
        Ti.API.error(err);
    }
});

Under the hood, this API uses the Backbone JS sync functionality. To have a solid understading of this libary, it will valuable to understand how does BackboneJS manages CRUD operations.

Special Properties

Custom Headers

Define your own custom headers. E.g. to add a BaaS API

"headers": {
	"Accept": "application/vnd.stackmob+json; version=0",
	"X-StackMob-API-Key": "your-stackmob-key"
}

Nested Result Objects

Lets say you have a REST API where the result objects are nested. Like the Twitter search API. It has the found tweets in a results object. Use the parentNode to specify from which root object you want to parse children objects.

config: {
	...
	"parentNode" : "results"
}

It has support for nested objects.

config: {
	...
	"parentNode" : "news.domestic"
}

Since v1.1.1 - you can specify this object as a function instead to custom parse the feed. Here is an example:

Feed: http://www.google.com/calendar/feeds/[email protected]/public/full?alt=json&orderby=starttime&max-results=15&singleevents=true&sortorder=ascending&futureevents=true

Custom parsing:

parentNode: function (data) {
	var entries = [];

	_.each(data.feed.entry, function(_entry) {
		var entry = {};

		entry.id = _entry.id.$t;
		entry.startTime = _entry.gd$when[0].startTime;
		entry.endTime = _entry.gd$when[0].endTime;
		entry.title = _entry.title.$t;
		entry.content = _entry.content.$t;

		entries.push(entry);
	});

	return entries;
}

ETag

This feature will only work if your server supports ETags. If you have no idea what this is, then consult your server admin. Start be enabling this feature in the model config, like the following:

config: {
	...
	"eTagEnabled" : true
}

You do not have to do anything more. The adapter will send and recieve the ETag for every single request and store those locally in the Ti.App.Properties namespace.

The adapter uses the IF-NONE-MATCH header to send the newest ETag for the provided url to the server on each request. Once a succesful response is recieved by the adapter, it will store the new ETag automatically.

Notice: This may be a good idea not to use this while developing, because it will cache and store your ETag - which might end up in wrong situations while you are working

Fetch data from POST requests

@Since v1.1.11 you can send requestMethod to fetch data from POST service

myModel.fetch({
	requestMethod: 'POST' // GET is default
})

Changelog

v1.1.13
BugFix for no responseText from a successful response

v1.1.12
Allow pass urlparams for model.destroy()

v1.1.11
Now you can set http request method in fetch, property name is requestMethod

v1.1.10
Bugfix for http headers after xhr.open() but before xhr.send()

v1.1.8
Bugfix for model.id #64 parentNode can be defined as a function #63

v1.1.5
Added ETag support
Bugfix for urlparams #34

v1.1.4
Added search mode

v1.1.3
Added support for accessing the error object. Issue #29 Thanks @alexandremblah

v1.1.2
JSON.parse errors are now caught. Thanks @FokkeZB

v1.1.1
Added support parentNode as a function for custom parsing. thanks @FokkeZB

v1.1.0
Added support for Nested Result Objects
Added support for Custom Headers
Code cleanup

v1.0.6
Added support for idAttribute

v1.0.5
Added HTTP Response code and error message

v1.0.4
Added debug

v1.0.3
Alloy 1.0.0.
Fix bug in rest url being global

v1.0.2
Added urlparams

v1.0.1
Android bugfixes

v1.0
init

Author

Mads Møller
web: http://www.napp.dk
email: [email protected]
twitter: @nappdev

License

The MIT License (MIT)

Copyright (c) 2010-2013 Mads Møller

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

napp.alloy.adapter.restapi's People

Contributors

brandonneil avatar claudijo avatar deweller avatar dulmandakh avatar falkolab avatar fokkezb avatar ftumsh avatar harrythree avatar hazemkhaled avatar jasonkneen avatar javenwang avatar leitom avatar pedrohatanasio avatar sophrinix avatar sukharenko avatar yomybaby avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

napp.alloy.adapter.restapi's Issues

Error when using ETag

Hi,

I am trying to add ETag support with "eTagEnabled" : true. The fist fetch works (before it has stored the ETag) but subsequent calls fail with the error shown below.

Do I need to add anything else to the model apart from eTagEnabled?

Script Error {
[ERROR] :      backtrace = "#0 parseJSON() at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:228\n#1 () at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:151\n#2 () at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:44";
[ERROR] :      line = 235;
[ERROR] :      message = "'null' is not an object (evaluating 'object[explodedString[i]]')";
[ERROR] :      name = TypeError;
[ERROR] :      sourceId = 326700576;
[ERROR] :      sourceURL = "file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js";
[ERROR] :  }
[ERROR] :  Script Error {
[ERROR] :      backtrace = "#0 parseJSON() at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:228\n#1 () at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:151\n#2 () at file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js:44";
[ERROR] :      line = 235;
[ERROR] :      message = "'null' is not an object (evaluating 'object[explodedString[i]]')";
[ERROR] :      name = TypeError;
[ERROR] :      sourceId = 326700576;
[ERROR] :      sourceURL = "file:///Users/tbp-it-bangor/Library/Application%20Support/iPhone%20Simulator/7.1/Applications/3AC4612C-7F65-497A-9A51-1668DB8AC304/tbp-mobile.app/alloy/sync/restapi.js";
[ERROR] :  }
[ERROR] :  2014-06-25 15:06:33.657 tbp-mobile[5117:70b] Warning: Attempt to present <TiErrorController: 0xd15c050> on <TiRootViewController: 0xd50ff60> while a presentation is in progress!

Output result to xml

Hi All,

How do i export the result to the view?

var api = Alloy.createCollection("api");
    api.fetch({
        url: "http://jsonplaceholder.typicode.com/posts",
        // uncomment and add data to post
        //data : {},
        add: true,
        silent: true,
        processData : false,
        success : function(_model, _response) {
            Ti.API.info(_response);
        },
        error : function(_model, _response) {
            Ti.API.info('Events Fetch Error');
            Ti.API.info(_response);
        }
    });

And my view

<Alloy>
    <Collection src="api"/>
    <Window class="container" onOpen="windowOpen">
        <TableView id="table" dataCollection="api">
            <TableViewRow>
                <Label text="{title}"></Label>
                <Label text="{body}"></Label>
            </TableViewRow>
        </TableView>
    </Window>
</Alloy> 

Can you tell me where i am going wrong?

Fetching a single model from the server

Any suggestion on how to do this. I've tried the following

var myModel =  Alloy.createModel('MyCollection');
myModel.fetch({id: 1});

but I get the error of "A url property or function must be specified" even though the "URL" is set

More docs?

Any way you can show some more examples. I get the one you have and have implemented it perfectly... however when trying to figure out how to use the adapter in a model things break down.

For instance using this as a model and not a collection is for some reason not working.

Could you give some quick examples of how to use this in a model context and send data using it as well?

Love to use this but need some more info if it's to be useful.

Fetching single model expects single element array rather than a plain object

My assumption is that a REST endpoint for a identified resource should return a plain key-value object, for example:
Request: GET /api/myResources/1234
Response: { id: '1234', name: 'whatever', ...}

But is seems that the alloy adapter expects the response with the single resource to be wrapped in an array, in order to parse the resource and create a backbone model, that is:

[ { id: '1234', name: 'whatever', ...} ]

.create method returning original json array along with response object

I have to do a post to an api, in my controller I have the following:

var param = {

    twitter : "dasd",
    nickname : "a",
    yob : '1876',
    description : "I am a test object"

};

matches.create(param, {
    success : function() {

        Ti.API.info("api response:"+JSON.stringify(matches));

    },
    error : function() {
        // something is wrong..
    }
}); 

The api responds with the original object and the object fetched by the server.

api response:[{"twitter":"dasd","nickname":"a","yob":"1876","description":"I am a test object","status":"OK","user":{"id":5188146770730811000,"auth_token":"WayXwJYEMVJaYfv2","facebook_id":"100005169690711","name":"John Smith","email":"[email protected]","description":"this is me"},"Id":"533fd3c2-24e3-b946-222a-e6d2e7235d04"}]

I have written a helper class without using your api (which works), but is based on creating apiRequest object via scratch and I never got the original object back - only the one the api fetches to me.

Is this a bug with your adapter? Thanks

Would be great to have a sample app for restapi.

I would be great to have sample app for restapi which covers all get,post,put,delete api with headers,url parameter and json parameter...If anyone has any sample created for this please link it here. Thanks

fetch using "POST" with data

here is my code:

myCollection.fetch({
url: myUrl,
requestMethod: 'POST',
data: data,
success : function(){
//some Code...
},
error : function(error){
alert(error);
}
});

i want to fetch my collection using post method,but i got error "data is not defined" at "data: data", can you give me an example how to do it?

thank you :)

accessing response code

Hey, I need to access response status or status code to handle errors in different situations. tried to pass _response to params.error() as third parameter, but no success. please advice.

for example, I need to know if error is due to 5xx or 4xx.

thank you

memory leak

ive got a memory leak in a very simple test case Ti Alloy app.

Mads, send me an email to [email protected] and I'll provide you a link to a shared folder so you can just download the Ti Alloy app and run it.

  1. run the app
  2. open Instruments and attach to this app
  3. filter by TiUI objects
  4. open and close the modal window 5 or 6 times

if fetch() is run WITH a callback eg,. fetch({success: function...}) .. , and then the modal window is closed - NONE of the objects in the modal window are released from memory (button, window, listview). next time the modal window is opened, then the objects just keep piling up in memory, until the app crashes.

however if you comment out the callback (per above), then all objects are eventually release and memory is clean.

i'd initially passed this on to Appcelerator support, however they've sent me to you to seek a solution to what they say is a third party (this adaptor) memory leak issue.

perhaps this is something very simple that i am missing in my code, in terms of releasing backbone object(s). if so please do let me know.

otherwise let me also know what your test results look like and if you too can see a memory leak.

txs
angus

Error after change idAttribute

I've set idAttribute to uuid. When trying to fetch data:

var court = Alloy.createModel('court', {"uuid": args["uuid"]});
court.uuid = args["uuid"];

court.fetch();

I have an error:

[ERROR] V8Exception: Exception occurred at alloy/sync/restapi.js:1: Uncaught TypeError: Cannot read property 'uuid' of null

Change the "URL" parameter dynamically by ID

I have a web-service that gives me back some JSON, if I make the request with an ID in the URL: http://mywebservice.com/api/user/<id>. In the example here on GitHub, the "URL" field is set statically, but is there a way to set it dynamically with a given ID? I tried overriding the url property in extendModel as well as in extendCollection but the console says TypeError: undefined is not a function (evaluating 'model.url()')

Header has to set before call xhr open

Headers (line 90-94)
Has to be moved before call "xhr.open" otherwise these settings get ignored.

I suggest to move these lines right after the xhr object have been return from "createHTTPClient"

FYI: fetch, 'add: true' and garbage collection

I had a log full of DEBUG/dalvikvm(509): GC_CONCURRENT freed 4688K, 23% free 18428K/23751K, paused 7ms+19ms when executing the callback of the apiCall method. Sometimes the app crashed, sometimes it would just take some time until it was useable again.

I called fetch with add: true to just append incoming results to my table. When I set it to false there was no GC issue. After a while of researching I combined it with silent: true and my issue was solved.

I don't know if this is a restapi.js issue, how I use restapi.js or an issue of the Backbone version of Titanium or maybe a combination of them all. But maybe my solution might help others who face the same problem and come here for help.

Nexus 4
Titanium 3.3.0
Alloy 1.4.1
Rest API Adapter for Titanium Alloy 1.1.5

Model Save does enter into success function

Not sure if this is just me but for model.save() the success callback is not called.

Here is my model

var BookModel = Alloy.createModel("Book");
BookModel.set('name','test Book');
BookModel.save({
success : function(){
Ti.API.info('Success');
},
error : function(){
Ti.API.error("hmm - this is not good!");
}
});

Thanks

Parsing array response from server

Hello,

I am trying to parse this output (from an API):

{
"code": 200,
"total": 1,
"projects": [
{
"project": {
"id": 4,
"title": "rebuilding school",
"description": "Rebuilding of the school diner.",
"created_at": "2013-09-24T15:59:10Z",
"total_tasks": 2
}
}
]
}

I tried both this:

"parentNode": "projects.project",

and I have tried this:

"parentNode": "projects[0]project",

None of them creates the model. How can I access the title, id and so on?

Thanks!

parentNode issues on PUT DELETE and UPDATE

If you have parentNode set for GET then you get errors on using PUT, DELETE, UPDATE etc if the returning JSON doesn't include that node.

Current workaround is doing this in the model config:

parentNode: function(data) {
    data = data || [];
    return data.tasks || data;
}

which will get around the issue and just pass back the data returned -- will look at how that could be integrated into the adapter.

No Promise Is Returned on Save

Either false or a Promise should be returned when the .save() method is called. As it is now, there is nothing returned (thus the return value is undefined).

See the Backbone save method.

Works but get the following error

Not sure if this is a problem with the API or something else, I am using deployd and get the following error on every API call. However I get exactly what I want back.

[ERROR] : �� �= "<KrollCallback: 0xc3a5490>";
[ERROR] : �� �    headers =     {
[ERROR] : �� �        "Content-Type" = "application/json";
[ERROR] : �� �    };
[ERROR] : �� �    parse = 1;
[ERROR] : �� �    success = "<KrollCallback: 0xc3a1da0>";
[ERROR] : �� �    type = GET;
[ERROR] : �� �    url = "http://localhost:2403/breeders";
[ERROR] : �� �}

No error object when request is failing...

Hi

I am trying to use this API for retrieving and updating data. If I do a collection.create and it fails, the code returns to the "error:" section. However, I have found no way to get a handle on the error message itself...

This is my code:

var model = Alloy.createCollection('Service');
model.create(buildServiceRequest(entity,dataType,action),{
    success: function(result){
        console.info("sendPostRequest result.toJSON(): " + JSON.stringify(result.toJSON()));
        // var response = (result && result.attributes) ? reßsult.attributes : null;
        var response = result.toJSON();
        if(response.success) {
            console.debug("call success callback");
            if(callBack) {
                callBack(response);
            }
        } else {
            console.debug("call error callback");
            if(errorCallBack) {
                errorCallBack(response);
            }
        }
    },
    error: function(result, x, e){
        var response = result.toJSON();
        console.debug("sendPostRequest response: " + JSON.stringify(response));
        console.error("sendPostRequest error: " + JSON.stringify(e));
        if(errorCallBack) {
            errorCallBack(response,e);
        }
    }
}); // Save data

'x' seemt to always be undefined. The output from the above code is:

[INFO] [iphone, 8.0, 192.168.42.38] sendPostRequest response: {"action":"login","dataType":"Credentials","data":{"user":"[email protected]","password":"dfdf","version":"1.0.0"}}
[ERROR] [iphone, 8.0, 192.168.42.38] sendPostRequest error: {"collection":[{"action":"login","dataType":"Credentials","data":{"user":"[email protected]","password":"dfdf","version":"1.0.0"}}],"i
ndex":0}
[INFO] [iphone, 8.0, 192.168.42.38] remoteLoginError: result.success=undefined, result.error=undefined
[ERROR] [iphone, 8.0, 192.168.42.38] result={"action":"login","dataType":"Credentials","data":{"user":"[email protected]","password":"dfdf","version":"1.0.0"}}
[ERROR] [iphone, 8.0, 192.168.42.38] [REST API] CREATE ERROR:
[ERROR] [iphone, 8.0, 192.168.42.38] {
"success": false,
"status": "error",
"code": 403,
"error": "HTTP error",
"responseText": "{"success":false,"error":{"id":"2","message":"Ugyldig bruger ([email protected]) eller kodeord"}}",
"responseJSON": {
"success": false,
"error": {
"id": "2",
"message": "Ugyldig bruger ([email protected]) eller kodeord"
}
}
}

So basically, I don't get the error back in my code. However, I can see it from the REST API as I have enabled debugging.

If I use a "fetch" instead and this error handling:

 var dataLastChanged = Alloy.createCollection('UserDataLastChanged');
    dataLastChanged.fetch({
        success : function(){
            _.each(dataLastChanged.models[0].attributes, function(element, index, list){
                // Loop through the first model returned. In the attributes we find the key/value pairs we are looking for
                :
                :
                  }
            });
        },
        error: function(result, e){
            console.error("Error msg: " + e);
        }
    }); // Grab data 

Then I get the valid error message (though only the message in localized language - and not a code to make it easier to check programmatically).
Am I doing something wrong? - or does the API not support returning the "real" error to my code?

Thanks in advance.

Edited 23 October - more complete code examples...

/John

add question mark if params.urlparams is empty

Hi,

I'm just beginning with Restapi in titanium, and I have a "read" to perform without url parameter.

At the line 128, you set params.urlparams with the urlparams or an empty Json object.

Is the purpose of the line 200 is to test if params.urlparams is empty?
If yes, it does not work. If no, how can I remove the "?" at the end of my url added by the function encodeData?

To test if a json object is empty, use the code:

function isEmpty(ob){
   for(var i in ob){
     return false;}
  return true;
}

Sending params with save()

I'm trying to save a model to an endpoint but I just can't figure out how to send the data:

var fav = Alloy.createModel('favourite');
fav.save({item_id: item._id}, {
    success: function(){
        Ti.API.info('Success');
    },
    error: function(){
        Ti.API.info('error');
    }
});

Also tried:

var fav = Alloy.createModel('favourite');
fav.set('item_id', item._id);
fav.save({}, {
    success: function(){
        Ti.API.info('Success');
    },
    error: function(){
        Ti.API.info('error');
    }
});

With debug on I can see the output:

"url": "http://localhost:4000/users/me/favourites", "data": "{}"

How do I send params along with the save?

Is possible to upload a file using the restapi?

I'm using this adapter to do the rest calls on my app, but know I need to upload a file in a post request. This is possible with this module?

Can someone provide an example? If it's possible I think should be on the documentation because is a important example.

HTTP Basic Auth implementation

I would like to use the adapter with HTTP Basic Auth.
It seems like I have to modify the file in order to have the "username" and "password" headers set.

It would be really useful to implements the method.

Can I change the URL in runtime?

After logging the user in, I need to send a token with the URL. The URL is in the config object of the model definition and I cannot seem to access it from my code.

Do you know a way to change the URL for this model, and fetch() again to use the new URL? Or is there a way to add custom GET/POST parameters in runtime?

Crash when fetch returns a null item

My responseJSON is [null] (which is a valid JSON response), and then the adapter starts looping on the items, trying to set item[model.idAttribute], e.g. https://github.com/viezel/napp.alloy.adapter.restapi/blob/master/restapi.js#L274
All such cases should be changed to something like:
if (item && item[model.idAttribute] === undefined)
Also note that https://github.com/viezel/napp.alloy.adapter.restapi/blob/master/restapi.js#L273 overwrites the empty object from the previous line, this is not the intent.

Custom idAttribute not recognized in Sync

My Rails/Mongoid app returns JSON with the _id attribute rather than id, so I have set the model.definition.config.idAttribute to '_id'. This works fine in the create case, but model[model.idAttribute] returns falsy in other cases. It appears that model.id would return the appropriate _id string. Am I doing something wrong, or should I modify my restapi.js?

Response structure on save

Hi,

First, thanks for creating this great adapter!
On fetching models and collections I have been serving the objects enclosed in an array like below:
{"meta":"","users":[{"username":"Michael","id":"1"}]}

However when creating a new model and posting to the api the adapter expects the response object without the array. Is this the expected behavior? Seems a little inconsistent.

Thanks,
Michael

Having trouble processing RESTapi response.

The issue

I am using RESTapi to interface with my Rails-based REST API. I am having issues parsing the response.

It GETs my data from the API fine. I can see the response JSON, but I am unable to pull the individual models out of the responded collection for processing. I'm sure I'm doing some thing obviously wrong.

BTW: I have validated the JSON response through both curl and jsonlint.

Code:

models/Job.js

exports.definition = {
    config: {
        URL: "http://192.168.1.137:5000/jobs",
        columns: {
            "id": "string",
            "job_id": "INTEGER PRIMARY KEY AUTOINCREMENT",
            "company_name": "string",
            "address1": "string",
            "address2": "string",
            "city": "string",
            "state": "string",
            "postal_code": "string",
            "country": "string",
            "account_id": "string"
        },
        adapter: {
            "type": "restapi",  // sql || restapi
            "collection_name": "Job",
            "idAttribute": "job_id"
        }
    },
    extendModel: function(Model) {      
        _.extend(Model.prototype, {
          /*
           * setAdapter: this allow for runtime swithcing
           * of sync adapter. It is mostly used to switch
           * between local sqlite and remote REST adapters
           */
          parse : function(_resp, xhr) { debugger;
            // return the post attributes
            return _resp;
          },
          doTest : function(msg){
            alert("job model do Test:"+msg);
          }

        });

        return Model;
    },
    extendCollection: function(Collection) {        
        _.extend(Collection.prototype, {

          doTest : function(msg){
            alert("job collection do Test:"+msg);
          }

        });

        return Collection;
    }
}

alloy.js

var jobs = Alloy.createCollection('Job');
jobs.setAdapter('restapi');
jobs.fetch();
Ti.API.info("job count before:"+jobs.length);

// handle response from jobs fetch
jobs.on('fetch', function(){
  Ti.API.info("jobs on change start");
  Ti.API.info("jobs response:"+JSON.stringify(jobs));
  Ti.API.info("jobs count after:"+jobs.length);

  for (var i=0; i<jobs.length; i++) {
    Ti.API.info("job "+JSON.stringify(jobs[i]));
  }
});

Response

[{"account_id":"1","address1":"123 Market Street","address2":"","city":"San Diego","company_name":"Knotty Barrel","country":"United States","created_at":"2013-03-21T09:34:24Z","id":"84c149ae-920a-11e2-9917-dc2b61fffee2","job_id":null,"postal_code":"92101","state":"CA","updated_at":"2013-03-21T09:34:24Z"},{"account_id":"1","address1":"800 The Mark Lane","address2":"Unit 1703","city":"San Diego","company_name":"The Mark","country":"United States","created_at":"2013-03-21T09:34:42Z","id":"8f69964a-920a-11e2-9917-dc2b61fffee2","job_id":null,"postal_code":"92101","state":"CA","updated_at":"2013-03-21T09:34:42Z"}]

Log

[INFO] [iphone, 6.1, 192.168.1.139] SyncHistory.getJobs() count:2
[INFO] [iphone, 6.1, 192.168.1.139] job undefined
[INFO] [iphone, 6.1, 192.168.1.139] job undefined

READ ERROR on fetch with data

Whenever I do a fetch with data I get an error of

[ERROR] :  [REST API] READ ERROR:
[ERROR] :  {
[ERROR] :      code = 0;
[ERROR] :      data = "Unable to parse JSON string";
[ERROR] :      error = "cannot parse response";
[ERROR] :      responseJSON = "<null>";
[ERROR] :      responseText = "cannot parse response";
[ERROR] :      status = error;
[ERROR] :      success = 0;
[ERROR] :  }
[ERROR] :  [REST API] apiCall ERROR: cannot parse response
[ERROR] :  [REST API] apiCall ERROR CODE: 0
[ERROR] :  [REST API] apiCall ERROR MSG: cannot parse response

here's how I'm fetching

events.fetch({
        data : {
            user : {
                email : Titanium.App.Properties.getString("email"),
                token : Titanium.App.Properties.getString("token")
            }
        },
        processData: true,
        success : function(_model, _response) {
            $.loading.hide();
        },
        error : function(_model, _response) {
            Ti.API.info('Events Fetch Error');
            Ti.API.info(_response);
        }
    });

I've also tried JSON.stringify on the data but that causes the same error.

Fetch with parameters turns the http method to 'POST'

When trying to fetch with some query string with the following:
Collection.fetch({ data: { query: 'some keyword' }, processData: true})
It turns the request into 'POST' to the server instead of 'GET'. When I try to pass the method in such as:
Collection.fetch({ data: { query: 'some keyword' }, processData: true, type: 'GET' })
It doesn't do anything different, still POSTing to the server. Is there an option to fetch the collection with query strings?

access error object

using your example, how can i access the error object ? its not clear to me how i can parse the error result data eg. code=404, data="HTTP error" , etc...

var collection = Alloy.createCollection("MyCollection"); //or model
//the fetch method is an async call to the remote REST API.
collection.fetch({
success : function(){
_.each(collection.models, function(element, index, list){
// We are looping through the returned models from the remote REST API
// Implement your custom logic here
});
},
error : function(){
Ti.API.error("hmm - this is not good!");
}
});

App crashes on fetch

Not too sure is this issue is for here but thought I'd start her anyway.

When my app launches it immediately crashes and closes with no error.

Model

exports.definition = {  
    config: {
        "URL": "http://www.example.com/api/events",
        "debug": 1, 
        "adapter": {
            "type": "restapi",
            "collection_name": "plugevents",
            "idAttribute": "nid"
        },
    },      
    extendModel: function(Model) {      
        _.extend(Model.prototype, {});
        return Model;
    },  
    extendCollection: function(Collection) {        
        _.extend(Collection.prototype, {});
        return Collection;
    }       
};

Fetch Collection

var collection = Alloy.createCollection("plugevents"); //or model
collection.fetch({ 
    success : function(){  
         Ti.API.info(collection.models);    
        _.each(collection.models, function(element, index, list){

        });
    },
    error : function(){
        Ti.API.error("hmm - this is not good!");
    }
});

If I remove

Ti.API.info(collection.models); 
``
the app doesn't crash.

How can I pass parameters?

I would like to get a specific user details from my API server.
How can I pass parameters with the fetch method with the user id? and possibly username & password?

Thanks

Unable to do a POST request

I want to POST some data to authenticate the user right know I have this:
var model = Alloy.createModel("login");

model.save({ 
    params: { 
        username: "username",
        password: "pass" 
    },
    //parse:false,
    success : function(e){
    },
    error : function(){
        Ti.API.error("hmm - this is not good!");
    },
});

But the website never receive the POST data. I don't now if is my problem or problem with the adapter.restapi

Update function works but sends the error response

Here is the REST API I am using http://rest.learncode.academy/api/learncode/something
everything(ADD, SELECT, DELETE) works fine except the UPDATE doesnt send the proper response:

function updateUser() {
      var params = {
	name: 'U222User',
	email: '[email protected]'
    };

    // UPDATE /userss/:id
    user.save(params, {
	success: function() {
		alert('suuccc');
	},
	error: function() {
		alert('THIS DOESNT WORK');
	}
    });
}

It updates the API, but alerts the ERROR , why?

Which version to use?

I see that you have versions of your restapi adapter. Which one is the current one? This one or the other?

This one is missing SQL queries (perhaps add here too?).

Thanks!

Android HTTP Error & JSON.parse

In Android, when the application receive a http error or exception as http 401 or 409 the JSON.parse return a V8Exception Uncaught SyntaxError: Unexpected end of input.

I'm resolve this problem changing the restapi.js line 153 to:

params.error((_response.responseText != "") ? JSON.parse(_response.responseText) : {}, _response.responseText);

PATCH support?

Hi,

Is there support for PATCH updates?
In the backbone docs you should be able to set {patch: true} on model.save.
When I do this it is still sending a PUT.

Thanks,
Michael

complex objects as urlparams cause errors

The following urlparams will cause and error because the encodeData function is only looking one level deep.

var project = Alloy.Collections.project;
project.fetch({
    urlparams: {
        fields: {title: 1, category: 1}
    },
    success: function (model, res) {
        Ti.API.info('Success');
    },
    error: function (model, res) {

    }
});

Writing your own object/array to URI query string converter seems like overkill for this adapter when there are other libraries that do this very well. While I can appreciate that this adapter has no dependencies, perhaps using a query string library would be beneficial to everyone. I added https://github.com/visionmedia/node-querystring to the adapter and it works great. Maybe we could use node-querystring ONLY if require can find it... and it could fall back to the encodeData function if not.

I could submit a patch if it's something you would be interested in.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.