I am new to Node.js and have an application in which there are multiple organizations with multiple admins and multiple groups with multiple users who can make multiple posts. Like this:
Organization
Admins
Groups
Users
Posts
Admins have access to everything within the organization. Their primary goal is to observe and analyze the posts their users are making. Admins can:
Get all posts by organization
Get all posts by group
Get all posts by user
Because there are three specific ways in which posts can be queried, I have built three separate routes and handler functions for each of the ways to query posts:
/api/posts/organization/:organizationID
/api/posts/group/:groupID
/api/posts/user/:userID
As I have learned more about RESTful APIs, everything I see tells me that "path params are used to identify a specific resource or resources, while query parameters are used to sort/filter those resources."
This is a bit confusing for a beginner like me. It seems like "posts" are the "specific resource" here, so I should change my API to have one api/posts/ route and use query params to filter them. Is that right?
There is no single best practice, and your approach seems reasonable. Typically I would structure this as:
/users/:id/posts
/groups/:id:/posts
/organization/:id/posts
As this makes the relationship more clear (posts that belong to users).
But your approach, and using 1 endpoint with query parameters are all reasonable approaches. The most important thing is to be consistent and ideally find an existing style guide to follow.
What matters here that you need to be able to identify your resources. The simplest approach is:
/api/posts/{postId}
/api/organizations/{organizationID}
/api/groups/{groupID}
/api/users/{userID}
As of the admin vs regular user, it is called role-based access control (RBAC). So roles can be another resource, though if you never want to edit them, then just hardcode them and manage roles by users and groups.
The path is for the hierarchical part of resource identification the query is for non-hierarchical part, but they sort of overlap, which is not a big deal, you can even support both. So the URI is a unique identifier, but it is not exlusive, you can have multiple URIs, which identify the same resource.
As of the query part, I like to use it for filtering collections and return always an array even if it contains one or zero items. So with my approach:
/api/users/{userID}
/api/users/?id={userID}
These two are not exactly the same, because the second one returns an array with a single item. But this is not a standard, just my preferred approach.
I like the upper simple URIs instead of the heavily nested ones and add more depth only if it grows really big. It is like namespacing in a programming language. For a while you are ok with the global namespace, but if it grows big, then you split it up into multiple namespaces.
In your case I think I would do it the opposite direction as you did:
Get all posts by organization: /posts/?organizationId={id}
Get all posts by group: /posts/?groupId={id}
Get all posts by user: /posts/userId={id}
Another approach is:
Get all posts by organization: /organizations/{id}/posts/
Get all posts by group: /groups/{id}/posts
Get all posts by user: /users/{id}/posts
You can even support both approaches simultaneously or a different approach you like better.
Tbh. when you do something that is really REST, then the URI structure does not matter this much from REST client perspective, because it checks the description of the hyperlink it gots from the server and does not care much about the URI structure. So the response should contain something like the following:
{
"type":"link",
"operation":"listPostsForOrganization",
"method": "get",
"uri": "/api/organizations/123/posts/",
}
And you use the API with the client like this:
let organization = await api.getOrganizationForUser(session.currentUser)
let posts = await api.listPostsForOrganization(organization)
Related
I did a google search, but I could not find what I really need.
I need to query an API, which have the same route, but with different parameters.
Example:
router.get('/items/:query, function(){})
In this case, I would search for all items
router.get('/items/:id, function(){})
Here, I would look for a specific item
At the core of your issue is that you are trying to specify two different resources at the same location. If you design your API to adhere to restful principles you'll see why that's not a wise choice. Here are two good starting points:
https://en.wikipedia.org/wiki/Representational_state_transfer
http://www.restapitutorial.com/lessons/whatisrest.html
In restful api's the root resource represents the item collection:
/api/items
...and when you specify an id that indicates you want only one item:
/api/items/abc123
If you really still want to accomplish what you asked in your question you'll need to add a url parameter like /items/query?query=true or /items/abc123?detail=true but this will be confusing to 99% of web developers who ever look at your code.
Also I'm not sure if you really meant this, but when you pass a variable named "query" to the server that seems to indicate that you're going to send a SQL query (or similar data definition language) from the client into the server. This is a dangerous practice for several reasons - it's best to leave all of this type of code on your server.
Edit: if you really absolutely positively have to do it this way then maybe have a query parameter that says ?collection=true. This would at least be understood by other developers that might have to maintain the code in future. Also make sure you add comments to explain why you weren't able to implement rest so you're not leaving behind a bad reputation :)
The issue is that without additional pattern matching there isn't a way Express will be able to distinguish between /items/:query and /items/:id, they are the same route pattern, just with different aliases for the parameter.
Depending on how you intend to structure your query you may want to consider having the route /items and then use query string parameters or have a separate /items/search/:query endpoint.
I use MEAN stack to develop an application.
I'm trying to develop a restful API to get users by first name or lastname
Should I write one get function to get the users for both firstname and lastname?
What is the best practice to write the URL to be handled by the backend?
Should I use the following?
To get user by firstname: localhost:3000/users?firstname=Joe
To get user by name:localhost:3000/users?firstname=Terry
And then check what is the parameter in my code and proceed.
In other words,What is the best practice if I want to pass one of multiple parameters to restful API and search by only one parameter?
Should I use content-location header?
There is no single best practice. There are lots of different ways to design a REST interface. You can use a scheme that is primarily path based such as:
http://myserver.com/query/users?firstname=Joe
Or primarily query parameter based:
http://myserver.com/query?type=users&firstname=Joe
Or, even entirely path based:
http://myserver.com/query/users/firstname/Joe
Only the last scheme dictates that only one search criteria can be passed, but this is likely also a limiting aspect of this scheme because if you, at some time in the future, want to be able to search on more than one parameter, you'd probably need to redesign.
In general, you want to take into account these considerations:
Make a list of all the things you think your REST API will want to do now and possibly in the future.
Design a scheme that anticipates all the things in your above list and feels extensible (you could easily add more things on to it without having to redesign anything).
Design a scheme that feels consistent for all of the different things a client will do with it. For example, there should be a consistent use of path and query parameters. You don't want some parts of your API using exclusively path segments and another part looking like a completely different design that uses only query parameters. An appropriate mix of the two is often the cleanest design.
Pick a design that "makes sense" to people who don't know your functionality. It should read logically and with a good REST API, the URL is often fairly self describing.
So, we can't really make a concrete recommendation on your one URL because it really needs to be considered in the totality of your whole API.
Of the three examples above, without knowing anything more about the rest of what you're trying to do, I like the first one because it puts what feels to me like the action into the path /query/users and then puts the parameters to that action into the query string and is easily extensible to add more arguments to the query. And, it reads very clearly.
There are clearly many different ways to successfully design and structure a REST API so there is no single best practice.
I'm looking into converting part of an large existing VB6 system, into .net. I'm trying to use domain driven design, but I'm having a hard time getting my head around some things.
One thing that I'm completely stumped on is how I should handle complex find statements. For example, we currently have a screen that displays a list of saved documents, that the user can select and print off, email, edit or delete. I have a SavedDocument object that does the trick for all the actions, but it only has the properties relevant to it, and I need to display the client name that the document is for and their email address if they have one. I also need to show the policy reference that this document may have come from. The Client and Policy are linked to the SavedDocument but are their own aggregate roots, so are not loaded at the same time the SavedDocuments are.
The user is also allowed to specify several filters to reduce the list down. These to can be from properties that are stored on the SavedDocument or the Client and Policy.
I'm not sure how to handle this from a Domain driven design point of view.
Do I have a function on a repository that takes the filters and returns me a list of SavedDocuments, that I then have to turn into a different object or DTO, and fill with the additional client and policy information? That seem a little slow as I have to load all the details using multiple calls.
Do I have a function on a repository that takes the filters and returns me a list of SavedDocumentsForList objects that contain just the information I want? This seems the quickest but doesn't feel like I'm using DDD.
Do I load everything from their objects and do all the filtering and column selection in a service? This seems the slowest, but also appears to be very domain orientated.
I'm just really confused how to handle these situations, and I've not really seeing any other people asking questions about it, which masks me feel that I'm missing something.
Queries can be handled in a few ways in DDD. Sometimes you can use the domain entities themselves to serve queries. This approach can become cumbersome in scenarios such as yours when queries require projections of multiple aggregates. In this case, it is easier to use objects explicitly designed for the respective queries - effectively DTOs. These DTOs will be read-only and won't have any behavior. This can be referred to as the read-model pattern.
I'm using CouchDB to store data coming from various sources and couchdb-lucene to allow ad-hoc queries. That's important for me because I display the data in a feed and I want this feed to be filterable. CL seems perfect for that.
However, I also want to introduce permissions to the feed app - a user should only be able to see a feed item if he/she has the permission to see it.
Now, I would like to be able to run ad-hoc queries and only return the feed items that the currently authenticated user has permissions to read.
The only solution that I could figure out (so far) was to add a 'permissions' field to each feed item where I store all the permission for the other users (obviously skipping the users that have no permissions for this item at all)
permissions: [{user_id: '123', read: true, write: true}, ...]
and then index this array in CL.
While this will probably work, I feel kind of bad being forced to nest the permissions metadata in the feed item...it might even be a better solution than keeping it separate, but I just don't like that I don't seem to have a choice here.
The only other solution (well, other than dumping CouchDB) would be to run the ad-hoc query without being concerned about the permissions, then run a second query on the server that selects all "my items" and do a set intersection. But those sets can be huge (and if I chunk it, it would require possibly many DB requests => slow).
Is my solution fine or is there anything better? Or is CouchDB just not a good fit for such queries?
Cheers!
You are on the right path with keeping that permission data on the document itself. This will be the easiest way for you to build views later on, which will enable you to check for user permissions. So dont worry and just let it flow in that direction. Feeling bad about nesting that data probably comes from previous ages when you were using SQL and RDBMS'es, where you'd want to normalize the hell out of each table. This time it's completely different :)
Btw, the only possibility to do "JOINS" in CouchDB is to use Linked Documents. If you are interested you can give that a try. However it wont enable you to look inside the linked document, while creating a view.
I am designing an API, and I'd like to ask a few questions about how best to secure access to the data.
Suppose the API is allowing access to artists. Artists have albums, that have songs.
The users of the API have access to a subset of all the artists. If a user calls the API asking for some artist, it is easy to check if the user is allowed to do so.
Next, if the user asks for an album, the API has to check if the album belongs to an artist that the user is allowed to access. Accessing songs means that the API has to check the album and then the artist before access can be granted.
In database terms, I am looking at an increasing number of joins between tables for each additional layer that is added. I don't want to do all those joins, and I also don't want to store the user id everywhere in order to limit the number of joins.
To work around this, I came up with the following approach.
The API gives the user a reference to an object, for instance an artist object. The user can then ask that artist object for the albums, which returns a list object. The list object can be traversed, and album objects can be obtained from it. Likewise, from an album object a songlist object can be obtained and from that, the individual song objects.
Since the API trusts the artist object, it also trusts any objects (albums in this case) that the user gets from it, without further checks. And so forth for all the other objects. So I am delegating the security/trust to objects down the chain.
I would like to ask you what you think of it, what's good or bad about it, and of course, how you would solve this "problem".
Second, how would you approach this if the API should be RESTful? My approach seems less applicable in that case.
Is this a real program or rather a sample to illustrate a question?
Because it is not clear why you would restrict access to the artists and albums rather than just to individual media items or even tracks.
I don't think that the joins should cost you that much, any half-smart DB system will do them cheaply enough when you are making a fairly simple criteria match on multiple tables.
IMHO, the problem with putting that much security logic into queries is that it limits your ability to handle more complex DRM issues that are sure to bound up. For example, what if the album is a collection from multiple artists? What if the album contains a track which is a duet and I only have access to one artist? etc, etc.
My view is that in those situations, a convenient programming model with sensible exception is much more important than the performance of individual queries, which you could always cache or optimize in the future. What you are trying to do with queries sounds like premature optimization.
Design your programming model as flexible as possible. Define a sensible sense of extensions, then work on implementing the database and optimize queries after profiling the real system.
It is possible that doing the joins is much faster than your object approach (although it is more elegant). With the joins you have only one db request, with the objects you have many. (Or you have to retrieve all the "possible" data in the first request, which could also slow down things)
I recommend doing the joins. If there is a problem about the sql you can ask at stackoverflow :D
Another idea:
If you make urls like "/beatles/whitealbum/happinesisawarmgun"
then you would know the artist in the begining of the request and could get the permission at once without traversing - because the url contains the traversal information. Just a thought.
It is a good idea to include a security descriptor for each resource and not only to a top-level one. In your example the security descriptor is simply artist's ID or a list of artists' IDs, if you support duets etc. So I would think about adding the list of IDs to both the artists and the songs tables. You can add a string field where the artist IDs for the resource will be written in comma-separated way.
Such solution scales well, you can add more layers without increasing time needed for security check. Adding a new resource also doesn't require any additional penalty except for one more field to insert (based on resource's parent field). And of course, this solution supports special situations described above (like more than one artists etc.).
This kind of solution also doesn't violate RESTful architecture.
And the fact that each resource contains its own security descriptor generalizes the resource's access permissions, making it possible to implement some completely different security policy in future (for example, making access permissions more granular, based on albums, not only artists).