kahmali / meteor-restivus Goto Github PK
View Code? Open in Web Editor NEWREST APIs for the Best of Us! - A Meteor 0.9+ package for building REST APIs https://atmospherejs.com/nimble/restivus
License: MIT License
REST APIs for the Best of Us! - A Meteor 0.9+ package for building REST APIs https://atmospherejs.com/nimble/restivus
License: MIT License
Some block comments in the code, but not others, start with "###*". Since your attention to detail is staggering, I was wondering if there was a particular meaning behind that - especially given the choice of pass-through comment blocks, vs. the regular #
- or if I shouldn't look too much into that as I dive into the code.
I need to disable clientside router which can be done via Router.options.autoStart = false;
, but need the Router exposed.
Use #51 and provide an API config option (something like useDefaultOptionsEndpoint
)
Not all apps use iron router, and it's kind of janky that you might need to disable the client part sometimes.
I've built a super ultra simple server-side JSON router here: https://github.com/stubailo/meteor-rest/tree/master/packages/json-routes
I would definitely be willing to modify it to accept the response as a return value, like you are using in this library.
Let me know if this is something you would be interested in merging.
Route paths are now case sensitive, as they should be. Use hyphenated, lowercase names for route paths, to conform to better practices. So api/some-long-route-name
instead of api/someLongRouteName
.
It took me a while to realize that I can't do..
Lists = new Mongo.Collection('lists');
Restivus.addCollection('lists');
..since if I do this I get
Error: A method named '/lists/insert' is already defined
at packages/ddp/livedata_server.js:1444:1
at Function._.each._.forEach (packages/underscore/underscore.js:113:1)
at [object Object]._.extend.methods (packages/ddp/livedata_server.js:1442:1)
at [object Object].Mongo.Collection._defineMutationMethods (packages/mongo/collection.js:886:1)
at new Mongo.Collection (packages/mongo/collection.js:208:1)
at Restivus.Restivus.addCollection (packages/nimble:restivus/lib/restivus.coffee:74:50)
at repl:1:10
at /Users/davidgolds/Desktop/kip/kipGameDB/.meteor/local/build/programs/server/shell.js:169:23
..So how can I have an API on a collection that I also want to manipulate elsewhere in my Meteor code!?
Hello,
I get this error when i try to start my app
Not migrating, already at version 5
Restivus configured at api/ without authentication
{"line":"52","file":"synced-cron-server.js","message":"SyncedCron: scheduled "Randomize Profile Random Sorter" next run @Wed Apr 22 2015 14:32:58 GMT+0000 (UTC)","time":{"$date":1429713178307},"level":"info"}
events.js:72
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE
at errnoException (net.js:905:11)
at Server._listen2 (net.js:1043:14)
at listen (net.js:1065:10)
at net.js:1147:9
at dns.js:72:18
at process._tickCallback (node.js:448:13)
Can you please guide me ?
Thanks!
Check out the following two deployed apps:
functional site
busted site
They are both supposed to show a homepage, but the second one shows the iron:router splash page. The only difference between them is that I initialized a RESTivus endpoint in the latter one.
The busted site still works fine on my local server -- it only gets confused and splash-screen-y when I deploy it. I've tried deploying to meteor and to heroku -- both produce the same result.
Is there a way to rate limit API calls? I couldn't find a build-in method, so how would you suggest to solve this?
Hello.
Everything works great before I turn on authentication. But when I attempt to connect to the login endpoint as follows, I get an error.
I'm doing a POST to
http://localhost:3000/api/login
with a body of
password=xyz&user=abc
The server generates the following response (which comes back to the client and is also generated from the meteor server in the command window):
TypeError: Cannot call method 'indexOf' of undefined
at [object Object].add.post (packages/nimble:restivus/lib/restivus.coffee:73:29)
at [object Object].Route.callEndpoint (packages/nimble:restivus/lib/route.coffee:121:25)
at [object Object].Router.route.action (packages/nimble:restivus/lib/route.coffee:40:40)
at boundNext (packages/iron:middleware-stack/lib/middleware_stack.js:251:1)
at runWithEnvironment (packages/meteor/dynamics_nodejs.js:108:1)
at packages/meteor/dynamics_nodejs.js:121:1
at [object Object].urlencodedParser (H:\ventureTrack.meteor\local\build\programs\server\npm\iron_router\node_modules\body-parser\lib\types\urlencoded.js:72:36)
at packages/iron:router/lib/router.js:277:1
at [object Object]..extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
at [object Object].hookWithOptions (packages/iron:router/lib/router.js:276:1)
Any ideas? I have set useAuth to true in the configure block.
Thanks!
Looks like this line causes meteor to crash when calling Restivus.configure()
and config.apiPath
isn't defined.
Can be fixed by adding existence checks :
if config.apiPath?[0] is '/'
config.apiPath = config.apiPath.slice 1
if config.apiPath?[-1] isnt '/'
config.apiPath = config.apiPath + '/'
When I try to update a record via a PUT request (I use the autogenerated endpoint), I get the following error:
Error: When the modifier option is true, all validation object keys must be operators. Did you forget
$set?
It seems that this has to do with literal document modifiers - how can I solve this since I can't influence the update call restivus executes (or can I?)
More info here: Meteor-Community-Packages/meteor-simple-schema#175
It would also be great if there was a way to only specify those fields in the request that need change (so the client does not have to submit the whole object when updating only one or two fields).
CC @stubailo (in case you decide to work on this)
I tried installing this per the readme, and then put the "quick start" javascript in my javascript file, and I get the following error on the server:
W20150506-11:44:08.203(-5)? (STDERR) /Users/x/.meteor/packages/meteor-tool/.1.1.3.1wysac9++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:245
W20150506-11:44:08.203(-5)? (STDERR) throw(ex);
W20150506-11:44:08.203(-5)? (STDERR) ^
W20150506-11:44:08.227(-5)? (STDERR) TypeError: Cannot read property 'name' of undefined
W20150506-11:44:08.227(-5)? (STDERR) at Restivus.Restivus.addCollection (packages/nimble:restivus/lib/restivus.coffee:96:38)
W20150506-11:44:08.227(-5)? (STDERR) at app/restivus.js:17:12
W20150506-11:44:08.227(-5)? (STDERR) at app/restivus.js:72:3
W20150506-11:44:08.227(-5)? (STDERR) at /Users/x/NetBeansProjects/restivusDemo/.meteor/local/build/programs/server/boot.js:222:10
W20150506-11:44:08.227(-5)? (STDERR) at Array.forEach (native)
W20150506-11:44:08.227(-5)? (STDERR) at Function..each._.forEach (/Users/x/.meteor/packages/meteor-tool/.1.1.3.1wysac9++os.osx.x86_64+web.browser+web.cordova/mt-os.osx.x86_64/dev_bundle/server-lib/node_modules/underscore/underscore.js:79:11)
W20150506-11:44:08.227(-5)? (STDERR) at /Users/x/NetBeansProjects/restivusDemo/.meteor/local/build/programs/server/boot.js:117:5
Hi I was wondering if there is some way I can limit what elements of a collection each user can see like the built in Meteor.publish function allows?
Can I pass a cursor to Restivus.addCollection()?
This is not a standard REST endpoint, and can be very destructive if accidentally included in a production environment. It should most likely be removed entirely.
The plan was to implement hooks in a fairly naive way: simply provide functions for adding each hook, which adds a hook into a list of functions that can call through to the next function. Then the endpoint will be instrumented with functions that will call through to the first hook in a specific list (e.g., calling the first hook in the onBeforeAuthHooks
list from the _onBeforeAuth
function immediately before we call the default or custom auth function). The order could be further configured by requiring hooks to be named and providing an option in the "addHook" functions that allows users to specify a hook they would like their's to run either before or after. All hooks will share the endpoint context.
Again, this is fairly naive, and would probably benefit from being implemented as connect middleware instead. I believe this is what is being done in Iron Router. The API would remain the same.
The following hooks are planned for all endpoints (in the order they should be called). Please leave a comment if you feel I missed something, or would like a hook added that is not listed here:
onStart
onBeforeAuth
onAfterAuth
onBeforeGet
, onBeforePost
, onBeforeDelete
, etc.onBeforeAction
onAfterAction
onAfterGet
, onAfterPost
, onAfterDelete
, etc.onBeforeResponse
onAfterResponse
onEnd
(This and onAfterResponse
may not need to be distinguished)I'm still unsure of exactly where to place the "after" method hooks. They could go before or after the response (or maybe another set of hooks is necessary?). Collections may need some of their own hooks (including a transform-style hook suggested in #12 by @dandv).
Whatever the implementation, it would be extremely beneficial to have this be pluggable. That way when auth and collections are broken up into add-on packages, they can take their hooks with them.
I have tried many ways to remove CORS but still failed.
"No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin "
I have tried this
Restivus.addRoute('cmsUsers', {authRequired: false}, {
post: {
authRequired: false,
action: function() {
this.response.setHeader('Access-Control-Allow-Origin', '*'); //ADDING THIS LINE
var doc = this.bodyParams;
if (Accounts.createUser(doc)) {
return {
headers: {
'Content-Type': 'text/json',
'Access-Control-Allow-Origin': '*'
},
body: {status: 'success'}
};
}
return {
headers: {
'Content-Type': 'text/json',
'Access-Control-Allow-Origin': '*'
},
statusCode: 500,
body: {status: 'fail', message: 'Internal Server Error'}
};
},
},
});
but still no luck for me. Please help, thanks
###*
comment style for all doc comments (those intended for both JSDoc and apiDoc)
useAuth
for endpoint authuseAuthEndpoints
to reflect it's actual purpose, which is to generate the default auth endpointsuseAuth
around for backwards-compatibilityFirst, I wanted to say a big thanks for your package - this is really great. The only issue I have is that data I add via a POST request is not available to the client without a page reload (if I'm assuming correctly this is because meteor does not update the published collection). How can I "republish" my collection so the client automatically gets the new entries?
201
: Resource created (from collection POST endpoint)403
: Role permission errors405
: API method not found (but route exists)
config:
defaultEndpoints:
post: ->
get: ->
put: ->
patch: ->
delete: ->
options: ->
Following the docs, I exposed only 1 endpoint for my collection:
Restivus.addCollection Collections,
endpoints:
get:
authRequired: true
action: ->
col = Collections.find(members: @userId)
if col
status: "success", data: col
else
statusCode: 400
body: status: "fail", message: "Unable to get collections"
but the complete collection is exposed. So I did some experiments - the following all expose the complete collection:
I added
excludedEndpoints: ['get']
but it still exposes the get call and the complete collection.
I tried returning just 'success', no data. Still I the call returns the complete collection
if col
status: "success"
else
statusCode: 400
body: status: "fail", message: "Unable to get collections"
I removed col = Collections.find(members: @userId)
and it keeps exposing the complete collection.
Now it gets even more interesting, I removed
authRequired: true
and I still get everything!
So I thought, lets try this with a customer route, following the docs:
Restivus.addRoute 'collections', authRequired: true,
get:
action: ->
col = Collections.find(members: @userId)
if col
status: "success", data: col
else
statusCode: 400
body: status: "fail", message: "Unable to get collections"
And guess what, I always get a
{
"status": "error",
"message": "You must be logged in to do this."
}
while I just succesfuly authenticated via /login
and the calling the endpoint with the headers as per the curl examples in the docs.
I don't know, this package seems very buggy. I also doubt @userid and @user being available in the endpoints. Doesn't log anything to console.
Any ideas?
Merely adding Restivus.configure()
to the Meteor skeleton app causes it to hang at the splash screen when meteor run ios
or meteor run ios-device
is executed.
Is there a way to always return the data array instead of the traditional formatted status
and data
request like so:
"data": [
{
"courseCredits": 4,
"name": "SEIS45",
"courseCode": "SESI452",
"description": "Great class",
"_id": "4a3nYgGSKTvZtbc5u"
}
]
In addition to adding tests for any new features, the test coverage for all the existing features should be expanded as much as possible.
endpoint_tests.coffee
, collection_route_tests
, etc.)When we have a call that requires authentication, we can still authenticate properly, but this.userId is blank when we reach that code.
This worked in 0.5.3, but was broken in 0.5.4.
Check out this branch, which shows an example of the behavior.
Not sure if this is possible, but to have more DRY code it would be useful to be able to
2. use meteor methods in endpoint actions
Because you already have your methods set up to do something with your collections. So if you could use those it means you don't have to duplicate code.
UPDATE: just figured out that is possible, with the exception that Meteor.userId() is not set. So if you protected your methods with check for userId the API can't run the method.
Question, we have an API where we generate an auth token for the user (accessible in their dashboard). They then pass that token as proof of authentication when making API calls. It would be cool if one could configure restivus to use alternative auth method; instead of the tokens generated via the login
endpoint.
I'm just thinking out loud here, but does that spark any thoughts?
Can you give an example request for how to log the user out like the one you gave with the login?
Hi fellow developers,
First of all, thanks to kahmali for this great package, it adds a lot to Meteor but the community doesn't seem to see its potential.
Why I'm saying this ? Well, because I believe that we can use Meteor as a normal Rest API with some other databases using node.js connectors.
Some will say : Meteor isn't made for that ! But seriously, stop thinking that Meteor is just for hacking some little projects and never use them at scale.
Personnaly, I have a serious project in mind, I would love to do it the Meteor way but also the classic way and I don't want to use 2 different frameworks to build the same app !
And this is a pretty basic scenario and I don't think that I'm the only one thinking about that. Let's use Meteor the same way we use Express or any other Rest framework and stop using it as a toy !
As a backend developer, my app has to integrate with many different clients that I DON'T CONTROL. Some want to use a Rest API, others don't.
Also, it would be great to see Meteor using other databases with all the connectors that node.js have, but not in a hacky way. There are great node.js ORMs like sequelize or bookshelf that are used in many other node.js frameworks like Express.
Why not use them with Meteor as they are used in the others ? (yes, we need to wrap the calls, but that's not a big problem and it makes the code looks cleaner).
I think that the community doesn't seem to see the true power of Meteor, and sadly it's seen like that outside of it because most of the other developers tell me that Meteor is just a toy to prototype but they would never use it for big scalable projects like they use Express.
I'm saying this to you and your community because I think this is the first step for Meteor to be used as a Rest API.
Thank you and sorry for this long post, I know this is not an issue, but I had anywhere else to talk about that because people (Meteor community) don't care, they just tell me to use Express instead...
Your SO answer in How to expose a RESTful web service using Meteor includes a great comparison with CollectionAPI, HTTP.publish and RestStop2. It would help users trying to decide between libraries if they could refer to the comparison. Since StackOverflow is notorious for deleting answers (as you've seen with Bill The Lizard wiping two of yours out), perhaps copying the content in this repo would be best.
I want to return a raw string as the response data but restivus wraps the string in double quotes.
return 'foo"bar'
Will produce
"foo\"bar"
I've tried setting the Content-type to text/plain or text/html but I get the same type of output.
What I ultimately want to do is return a JPEG image from a custom collection/:id/photo
route that extracts the base64-encoded image from a document.
First of all, thanks for a great package. Very easy to setup and functions well.
Now to the problem: I'd like to use restivus for both REST-stuff, and also for a few lower-level HTTP calls where I'm writing back binary data in chunks at a callback. I know that's not really anymore the scope of this package (REST), but as it 'almost' seems to work, would it be possible to implement?
Basically, in get() function, I hooked to @response object, and write(..) data there. After it's done, I do @response.end().
Restivus.addRoute 'test', { authRequired: false }, get: ->
_this = @
_this.response.write("test1")
setTimeout(->
_this.response.write("test")
_this.response.end()
, 1000)
return null
The above code writes "test1" to the client, but not "test", probably as restivus has already closed the connection. Could there be a parameter that would indicate that method will not return anything and will take care of ending the response?
Also, restivus logs following error:
TypeError: Cannot read property 'body' of null at [object Object].Router.route.action (packages/nimble:restivus/lib/route.coffee:53:24)
Is there any way to hook API before or after GET, POST, PUT, DELETE etc?
Thanks
I just installed the package, copy-pasted your exact quick-start example and placed it on my server. I get this error
W20150303-13:31:01.828(1)? (STDERR) throw(ex);
W20150303-13:31:01.828(1)? (STDERR) ^
W20150303-13:31:01.838(1)? (STDERR) TypeError: Property 'users' of object #<Object> is not a function
I run a very basic setup.
When I make a "GET" call I always get this error "TypeError: Cannot read property 'body' of undefined".
Here is my code:
Devices = new Mongo.Collection('devices');
// API must be configured and built after startup!
if(Meteor.isServer) {
Meteor.startup(function () {
// Global configuration
Restivus.configure({
useAuth: false,
prettyJson: true
});
Restivus.addRoute('devices', {
get: function () {
console.log("GET fired");
}
});
});
}
Error message
I20150309-14:08:57.145(1)? GET fired
W20150309-14:08:57.201(1)? (STDERR) TypeError: Cannot read property 'body' of undefined
W20150309-14:08:57.201(1)? (STDERR) at [object Object].Router.route.action (packages/nimble:restivus/lib/route.coffee:53:24)
W20150309-14:08:57.201(1)? (STDERR) at boundNext (packages/iron:middleware-stack/lib/middleware_stack.js:251:1)
W20150309-14:08:57.201(1)? (STDERR) at runWithEnvironment (packages/meteor/dynamics_nodejs.js:108:1)
W20150309-14:08:57.202(1)? (STDERR) at packages/meteor/dynamics_nodejs.js:121:1
W20150309-14:08:57.202(1)? (STDERR) at [object Object].urlencodedParser (/Users/bb/.meteor/packages/iron_router/.1.0.7.j8ckia++os+web.browser+web.cordova/npm/node_modules/body-parser/lib/types/urlencoded.js:72:36)
W20150309-14:08:57.202(1)? (STDERR) at packages/iron:router/lib/router.js:277:1
W20150309-14:08:57.202(1)? (STDERR) at [object Object]._.extend.withValue (packages/meteor/dynamics_nodejs.js:56:1)
W20150309-14:08:57.202(1)? (STDERR) at [object Object].hookWithOptions (packages/iron:router/lib/router.js:276:1)
W20150309-14:08:57.202(1)? (STDERR) at boundNext (packages/iron:middleware-stack/lib/middleware_stack.js:251:1)
W20150309-14:08:57.202(1)? (STDERR) at runWithEnvironment (packages/meteor/dynamics_nodejs.js:108:1)
Reproduction repo: https://github.com/dandv/webix-restivus
Demo: http://webix-restivus.meteor.com/
The bug summary is the naive observation. Looking at the console shows a Reference error "Route is not defined" at nimble-restivus.js line 124:
route = new Route(this, path, options, methods);
When deployed with --debug
, the deployed app also continues to run, and shows the grid, just as the locally run app does. BTW, should --debug
cause this difference? CC @stubailo.
This is ultimately caused by Restivus.addCollection being called on the client via lib
.
Is there a way to return a result asynchronously like so?
Restivus.addRoute 'people', authRequired:true,
post:
action: ->
person = new Person()
person.save (err, result)->
if err?
statusCode: 400
body: status: "fail", message: "Unable to create person"
else
"Person saved!"
One way to describe a RESTful interface is via WADL, the Web Application Description Language. There are lots of Java tools that convert WADL to REST, but nothing for meteor (and almost nothing for JavaScript, in fact).
Could this be an option for RESTivus? Or perhaps a package built on top of RESTivus?
Hi guys,
Its possible to authenticate with an external service like github / twitter or this feature is only available with local (loginWithPassword).
thks !!
Even when all tests pass the Travis CI build still fails.
Hi, Im getting this error:
Error: Meteor.userId can only be invoked in method calls. Use this.userId in publish functions. at Object.Meteor.userId
Im just create this file (/server/services/rest_services.js):
Restivus.configure({
apiPath: 'api/',
useAuth: true,
prettyJson: true,
enableCors: true
});
Restivus.addRoute('user/email_change/:email', {authRequired: false}, {
get: function () {
}
});
Why do you think this happens ?
In a custom route I would like to have multiple values as queryParams like this (e.g. value1 and value2):
...domain/api/update?key=1234&value1=10
How do I get them in endpoint function?
When I try this I get undefined:
var query = this.queryParams.key // result: 1234
var value1 = this.queryParams.value1 // result: undefined
This is my code in a new standard Meteor project with only Restivus package added.
Meteor version 1.0.3.2
// Create collection
Posts = new Mongo.Collection("posts");
if (Meteor.isServer) {
Meteor.startup(function () {
// RESTIVUS
// Global configuration
Restivus.configure({
useAuth: false,
prettyJson: true
});
// Given the url: "/posts?key=1234&value1=10"
Restivus.addRoute('posts', {
get: function () {
var key = this.queryParams.key;
var value1 = this.queryParams.value1;
console.log("key: " + key); // result: 1234
console.log("value1: " + value1); // result: undefined
}
});
});
}
Hi
I would like to authenticate using native device IOS token, i found a great post that seems to provide half the answer at this http://stackoverflow.com/questions/18118503/how-can-i-login-to-meteor-with-native-device-facebook. That would technically authenticate the user into the meteor stack, however my question is how would i go about using that to get a token for restivus? (/api/login)
Thanks
In my application I need the capacity to accept files via a POST request, my app uses yogiben:autoform-file
for file uploads. Is there a way to achieve this?
I have a RESTful API set up with useAuth turned on. Whenever I try to access /api/login with a valid username and password, I get this error:
curl --data "password=123123&user=peter" http://localhost:3000/api/login/
TypeError: Cannot read property 'config' of undefined
at [object Object].Restivus.add.post (packages/nimble:restivus/lib/restivus.coffee:93:18)
at [object Object].Route._callEndpoint (packages/nimble:restivus/lib/route.coffee:121:25)
at [object Object].Router.route.action (packages/nimble:restivus/lib/route.coffee:40:40)
at boundNext (packages/iron:middleware-stack/lib/middleware_stack.js:251:1)
at runWithEnvironment (packages/meteor/dynamics_nodejs.js:108:1)
That spot corresponds to this call in restivus.coffe:
@Restivus.config.onLoggedIn.call this
So presumably something's gone weird with "this" such that this.Restivus is undefined. Maybe an easy fix?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.