mulesoft-labs / osprey-router

Simple middleware-style router for RAML based on router
Other
4 stars 8 forks source link

Example #5

Closed robjens closed 9 years ago

robjens commented 9 years ago

Hi, I've been looking at implementing part of the Facebook API which happens to have some of the same structure in terms of (base) resources as the one used in your example.

As a matter of fact: /{user_id} although here is used /{userId}, I would assume these are not considered equal forms of the same resource?

Also, in scope of using Osprey, I cannot use these kind of paths as they would simply resolve to a Cannot GET /v1/1234 (for example).

Any chance you could enlighten me on this, I would be grateful. Thing is, the example shown in README doesn't offer for much 'out-of-the-box' working hello world when there isn't a (api).raml file to go along with it. So either providing a inline version in README, or as a file, might be handy... either way, as it sits now, I can't get it to work/duplicate.

blakeembrey commented 9 years ago

You're correct, those two keys are different. They'd need to match.

Are you using Osprey or the router here? There shouldn't be any issues with the router and the example on the README covers most of what the router does - it's made to implement named parameters into a router.

Can you post some example code for me to review? That would really help me figure out what's going wrong.

If you're interesting in using RAML, you might be looking for https://github.com/mulesoft/osprey which has a few examples including using the router.

robjens commented 9 years ago

Hey Blake,

Ah so what you say is, the use of a route e.g. /{userId} would translate to something like example.com?userId=1234?

What I mean to ask is, how would this translate in a concrete route (examples from graph.facebook.com):

GET /v2.0/{comment-id} HTTP/1.1 or GET /v2.0/{user-id} HTTP/1.1 and a nested one,

GET /v2.0/{object-id}/comments HTTP/1.1

The thing I must be confused about is that these are HTTP GET requests, so I wondered how would one -known- (on the API) side that the {user-id} is a user-id and not say a {comment-id}. Unless this is assumed to have come through prior calls, is this because in an earlier request we supposed to have gotten the resource? See, I've got this picture in my head of the typical: /resource/123/comments/234/ kind of path, so I ask myself, how does it work? Does it cache the previous request? Is there other logic supposed to translate these what appear to be UUIDs for generic (base) objects?

So my impression was that there would be calls to the API like e.g.:

/v2/1234/comments ;=> ok an object-id, but -what- object? and how come object-id and not say photo-id?

/v2/4567/ ;=> could be a Page? User-Id? Something else?

I guess my brain is a bit stuck on this part. Caching? Some kind of schema magic? Probably all the stuff I read assume this kind of prior knowledge to be present hides

Cheers and thanks,

Rob

blakeembrey commented 9 years ago

Ok, so this router is very similar to using Express or router, etc. It's very simple and doesn't do anything too crazy, it's just a little extra layer to provide routes validated in the style of RAML (E.g. by providing the type, minLength, etc.).

Say on the README you have the router like /{userId} - the key in the object must match it to provide the correct validation (assuming you want it to come out at all, otherwise it's treated as a string in the match and hidden from the route). In URL terms, this means it's matching /123, /456, etc. as we made it an integer. It will not match /abc or /123.1.

If you want to use a route like /resource/123/comments/234 you'd set up the router to handle it something like /resource/{resource-id}/comments/{comment-id} and pass something like { 'comment-id': { type: 'integer' }, 'resource-id': { type: 'integer' } } to validate them as integers.

The router itself is entirely stateless, so no magic here. Have you used Express before? That would probably be the most familiar paradigm. The name just aligns with the schema and the req.params object at runtime. You'll need to actually map it to a resource yourself, it won't automatically populate this. An example of this is in the router repo though, using the param method: https://github.com/pillarjs/router#routerparamname-param_middleware. You can do the same here.

Not sure if that's exactly where you were going with your comment, but it's an interesting discussion to have around automagically mapping object. Not for this project though.

As for the comments around /v2/1234/comments and /v2/4567 this is where the idea of APIs kick in. In general, having that route would not be useful. You should have something like /v2/comments/{id} and /v2/pages/{id}, etc. to know what is being queried for.

Does this clear anything up for you?

robjens commented 9 years ago

Right, this is what I expected, in the case of a route e.g. /resource/123/comments/234 kind of paths. But in fact I've never seen express routes that start with the colons e.g. /:resourceId/comments/:commentId. But as I understand this, and you confirmed it:

You should have something like /v2/comments/{id} and /v2/pages/{id}, etc. to know what is being queried for.

So something I have for routes:

Path "/{page_id}/videos/uploaded" not secured with "oauth_2_0"
Path "/{page_id}/ratings" not secured with "oauth_2_0"
Path "/{page_id}/posts" not secured with "oauth_2_0"
Path "/{payment_id}" not secured with "oauth_2_0"
Path "/{payment_id}/dispute" not secured with "oauth_2_0"
Path "/{payment_id}/refunds" not secured with "oauth_2_0"
Path "/{photo_id}" not secured with "oauth_2_0"
Path "/{photo_id}" not secured with "oauth_2_0"
Path "/{photo_id}/tags" not secured with "oauth_2_0"
Path "/{photo_id}/tags" not secured with "oauth_2_0"

Would, although technically be possible from the API design perspective (variable first part of the path) and allowed by the spec, since let's assume they are all integers, imply that there is a translation (middleware) mechanism being able to distinguish one id from the other.

So perhaps this is the minor point of 'critique' I had, if any, with the README example of /{userId} is that it raised this question of "How does it fit in, in practical real-world scenario".

Thank you very much for taking the time and effort to educate/inform me, really appreciate it.

blakeembrey commented 9 years ago

No worries, I can try making it a little more obvious. I guess I made a few assumptions about API knowledge that others would have. For those paths you sent me, you'll want to prefix each one with the type to be able to distinguish them - basically it acts as a stack and it'll match routes sequentially so if they overlap at all you'll run into trouble. The name is just a placeholder for you application to provide better context (and in your RAML, of course, because having {id} everywhere isn't very descriptive).

I'm going to close this out now, but feel free to keep opening more issues with other questions or ask more on this thread.